Codeforces Round #225 (Div. 2)(B思維題,E:dfs+樹狀陣列)

u010660276發表於2014-02-01

A. Coder

題意:在一張網格上放置棋子,他能攻擊到上下左右的地方,問最多放多少棋子,使其不能相互攻擊到,輸出一種方法;

思路:從第一個開始放,標記其上下左右。

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int maxn=1005;
char grid[maxn][maxn];
bool vis[maxn][maxn];
int n,ans;
void init()
{
    ans=1;
    for(int i=1;i<=n;i++)
        for(int j=1;j<=n;j++)
        {
            grid[i][j]='.';
            vis[i][j]=false;
        }
}
int main()
{
    cin>>n;
    init();
    grid[1][1]='C';
    vis[1][1]=vis[1][2]=vis[2][1]=1;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
            if(!vis[i][j])
            {
                grid[i][j]='C';
                ans++;
                vis[i][j]=vis[i+1][j]=vis[i-1][j]=vis[i][j-1]=vis[i][j+1]=1;
            }
    }
    cout<<ans<<endl;
    for(int i=1;i<=n;i++)
        cout<<grid[i]+1<<endl;
    return 0;
}

B. Multitasking

思路:直接模擬,剛開始算錯複雜度了,應該是m^2*n,想成n^2*m了,按步驟最多的寫就可以了,後來看了別人的程式碼,瞬間感覺弱爆了,直接輸出就可以。。。

#include <map>
#include <cmath>
#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 102;

int g[maxn][maxn];
int r[maxn];
struct node{
    int ll, rr;
}q[maxn * maxn];
int main(){
    int n, m, k;
    while (scanf("%d %d %d",&n,&m,&k)!=EOF){
        int a, b;
        for (int i=0; i<n; i++){
            for (int j=0; j<m; j++){
                scanf("%d",&r[j]);
            }
            for (int j=0; j<m; j++){
                for (int l=j+1; l<m; l++){
                    if (k == 0 && r[j] > r[l]){
                        g[j][l] = 1;
                    }
                    if (k == 1 && r[j] < r[l]){
                        g[l][j] = 1;
                    }
                }
            }
        }
        int tp = 0;
        for (int i=0; i<m; i++){
            for (int j=0; j<m; j++){
                if (g[i][j]){
                    q[tp].ll = i;
                    q[tp++].rr = j;
                }
            }
        }
        printf("%d\n",tp);
        for (int i=0; i<tp; i++){
            printf("%d %d\n",q[i].ll+1,q[i].rr+1);
        }
    }
    return 0;
}

#include <cstdio>
using namespace std;
int main()
{
	int n,m,k;
	scanf("%d%d%d",&n,&m,&k);
	printf("%d\n",(m*m-m)/2);
	for(int i=1;i<=m;i++)
		for(int j=i+1;j<=m;j++)
			if(k==0)
				printf("%d %d\n",i,j);
			else
				printf("%d %d\n",j,i);
	return 0;
}

C. Milking cows

思路:只需要計算每頭朝左的牛右邊所有朝右的牛的個數,然後求和就可以。或者反過來算也行。

#include<iostream>
using namespace std;
typedef long long LL;
LL n,ans,sum;
int main()
{
    cin>>n;
    ans=sum=0;
    int k;
    for(int i=0;i<n;i++)
    {
        cin>>k;
        if(k==1)
        sum++;
        else ans+=sum;
    }
    cout<<ans<<endl;
    return 0;
}

E. Propagating tree(參考)

題意:有一顆n個結點的有根樹,每個結點有一個值a[i],可以對樹進行以下兩種操作:

1、"1 x val" 把結點x的值加val,同時把結點x的兒子的值加上-val,結點x的兒子的兒子加上val,等等依次這樣進行

2、"2 x"查詢結點x的值

思路:由於第一個操作是對整個以x為根的子樹進行修改,因此我們可以利用dfs序把整個子樹重新編號為連續的區間,然後與結點x的樹高的奇偶性相同的兒子結點是加val,否則就是加-val,一般我們我們遇到的區間操作都是,對某個區間進行同一種修改操作,但是此題是結點的奇偶性不同,操作不同,如果我們用一顆線段樹或者樹狀陣列的話搞起來很麻煩,我們可以根據結點的奇偶搞兩顆BIT,然後根據結點x的奇偶性對對應的BIT進行相應的區間修改操作,查詢也是根據結點的奇偶性在對應的BIT上進行查詢

下面是程式碼:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn=200100;
struct node
{
    int v,next;
}edge[2*maxn];
int n,m,step=0,num=1;
int deg[maxn],high[maxn],tree[2][maxn],vis[maxn],low[maxn],a[maxn],head[maxn];
void add_edge(int u,int v)
{
    edge[num].v=v;
    edge[num].next=head[u];
    head[u]=num++;
}
void dfs(int u,int flag)
{
    low[u]=++step;//記錄到達當前節點的時間
    deg[u]=flag;//標記當前節點的奇偶性
    vis[u]=1;
    for(int i=head[u];i!=-1;i=edge[i].next)
    {
        if(!vis[edge[i].v])
            dfs(edge[i].v,(flag+1)%2);
    }
    high[u]=step;//記錄當前節點能管轄的範圍
}
void add(int x,int val,int flag)
{
    while(x<=n)
    {
        tree[flag][x]+=val;
        x+=x&(-x);
    }
}
int sum(int x,int flag)
{
    int ans=0;
    while(x>0)
    {
        ans+=tree[flag][x];
        x-=x&(-x);
    }
    return ans;
}
int main()
{
    //freopen("in.txt","r",stdin);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
    memset(head,-1,sizeof(head));
    for(int i=1;i<n;i++)
    {
        int u,v;
        scanf("%d%d",&u,&v);
        add_edge(u,v);
    }
    memset(vis,0,sizeof(vis));
    memset(tree,0,sizeof(tree));
    dfs(1,0);
    int op,x,val;
    for(int i=0;i<m;i++)
    {
        scanf("%d%d",&op,&x);
        if(op==1)
        {
            scanf("%d",&val);
            add(low[x],val,deg[x]);
            add(high[x]+1,-val,deg[x]);
            add(low[x],-val,(deg[x]+1)%2);
            add(high[x]+1,val,(deg[x]+1)%2);
        }
        else cout<<a[x]+sum(low[x],deg[x])<<endl;
    }
    return 0;
}


相關文章