Codeforces Round #225 (Div. 2)(B思维题,E:dfs+树状数组)

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;
}


  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值