hdu3887 (模拟栈+树状数组 ) &poj 3321 apple tree

首先说一下hdu的题意是输出每一个点的子树中比他小的点的个数。

poj的题意是输出子树的节点数,这基本就算是一个题了。

本来是不断地dfs就好了,但是这个栈的内存会爆,学长说了,C++不是可以手动扩栈吗,

然后就加上这一句#pragma comment(linker, "/STACK:102400000,102400000")

但是我问他区域赛可以吗,他说只要你不写错,一般不会的,还有一种什么模拟栈,然后就花了一天学了一下,就是不断的入栈和出栈,

然后加上一个树状数组各种搞

因为之前树状数组只是简单的运用一下,也不是很摸得透。今天顺带复习了一下,感觉还是蛮好的。

代码如下:

#include <cstdio>
#include <cstring>
#include <stack>
using namespace std;
#define maxx 100010
int head[maxx*2],par[2*maxx];
int l[maxx],r[maxx];
int ans[maxx];
int vis[maxx];
int cnt,toa;
int n,m;
stack <int >ss;
struct node {
    int s,next;
}edge[maxx*2];
void  add(int x,int y){
  edge[toa].s=x;edge[toa].next=head[y];head[y]=toa++;
}
int lowbit (int x){
   return x&-x;
}
int sum(int x){
   int r=0;
   while(x>0){
    r+=par[x];
    x-=lowbit(x);
   }
   return r;
}
void update(int x,int a){
   while(x<2*maxx){
    par[x]+=a;
    x+=lowbit(x);
   }
}
void dfs(int root){
    cnt=1;
   while(!ss.empty())
    ss.pop();
    memset(vis,0,sizeof(vis));
   ss.push(root);
   while(!ss.empty()){
    int u=ss.top();
    if(!vis[u]){
        l[u]=cnt++;
        vis[u]=1;
    }
    int flag=0;
    for(int i=head[u];i!=-1;i=edge[i].next){
        if(!vis[edge[i].s]){
            flag=1;
            head[u]=edge[i].next;//把u的next标记到当前节点,在调用的时候就可以跳过这一个了,本来以为这个可以优化好多时间的,谁知道只快了10ms。。。。
            ss.push(edge[i].s);
            break;
        }      
    }
    if(flag) continue;
    if(vis[u]){
        r[u]=cnt++;
        ss.pop();
    }
   }
}
void slove (){
   for(int i=1;i<=n;i++){
     ans[i]=sum(r[i]-1)-sum(l[i]);//看不懂自己把r[i],l[i]打印出来好好研究一下,
     update(l[i],1);
   }
}
int main(){
    while(scanf("%d%d",&n,&m)&&(n||m)){
        memset(head,-1,sizeof(head));
        memset(par,0,sizeof(par));
        toa=0;
        int a,b;
        for(int i=0;i<n-1;i++){
            scanf("%d%d",&a,&b);
            add(a,b);//建立邻接表
            add(b,a);
        }
        dfs(m);
        slove();
        for(int i=1;i<n;i++)
            printf("%d ",ans[i]);
        printf("%d\n",ans[n]);
    }
}

poj apple tree

这个题的坑就是我看题一直以为只删点,wa了几发,才看到摘或长出来,摘了就长出来,长出来就摘。

即用一个数组标记他是否被摘,如果被摘,那么就+1

else   -1;


#include <cstdio>
#include <cstring>
#include <stack>
using namespace std;
#define maxx 100010
int head[maxx*2],par[2*maxx];
int l[maxx],r[maxx];
int ans[maxx];
int vis[maxx];
int vis1[maxx];
int cnt,toa;
int n,m;
stack <int >ss;
struct node {
    int s,next;
}edge[maxx*2];
void  add(int x,int y){
  edge[toa].s=x;edge[toa].next=head[y];head[y]=toa++;
}
int lowbit (int x){
   return x&-x;
}
int sum(int x){
   int r=0;
   while(x>0){
    r+=par[x];
    x-=lowbit(x);
   }
   return r;
}
void update(int x,int a){
   while(x<2*maxx){
    par[x]+=a;
    x+=lowbit(x);
   }
}
void dfs(int root){
    cnt=1;
   while(!ss.empty())
    ss.pop();
    memset(vis,0,sizeof(vis));
   ss.push(root);
   while(!ss.empty()){
    int u=ss.top();
    if(!vis[u]){
        l[u]=cnt++;
        vis[u]=1;
    }
    int flag=0;
    for(int i=head[u];i!=-1;i=edge[i].next){
        if(!vis[edge[i].s]){
            flag=1;
            head[u]=edge[i].next;
            ss.push(edge[i].s);
            break;
        }
    }
    if(flag) continue;
    if(vis[u]){
        r[u]=cnt++;
        ss.pop();
    }
   }
}
int main(){
        while(scanf("%d",&n)!=EOF){
        memset(head,-1,sizeof(head));
        memset(par,0,sizeof(par));
        memset(vis,0,sizeof(vis));
        toa=0;
        int a,b;
        for(int i=0;i<n-1;i++){
            scanf("%d%d",&a,&b);
            add(a,b);
            add(b,a);
        }
         dfs(1);
         for(int i=1;i<=n;i++){
          update(r[i],1);
        }
        int T;
        scanf("%d",&T);
        while(T--){
            char op[2];
            scanf("%s",op);
            if(op[0]=='C'){
                    scanf("%d",&a);
                    if(!vis1[a]){
                    update(r[a],-1);
                    vis1[a]=1;
                    }
                    else {
                        update(r[a],1);
                        vis1[a]=0;
                    }
            }
            else
            {
                scanf("%d",&b);
                printf("%d\n",sum(r[b])-sum(l[b]));
            }
        }
        }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值