2016 湖南省赛 Tree Intersection csu 1811 区间统计颜色 (主席树 or 树状数组)

题意:问你每条边,在只有这个边不考虑的情况下,两个数共有颜色的数目。

解:

可以转化为 dfs许的情况下,求一段区间的的颜色数目和一段区间独有的颜色数目。

1、求一段区间的颜色数目是一个经典题目,拓展还有求一段区间每一个颜色最多贡献k的情况下有多少个这种题目

(1)利用主席树求  pre[i]值小于l的点有多少个

(2)这一部分也可以用树状数组统计出来,  也是对询问的右端点排序然后,我们没看到一个点先删掉前面的影响,

for(int i=1,j=1;i<n;i++){
        while(j<=que[i].r){
            if(pre[a[vis[j]]]){
                add_t(pre[a[vis[j]]],-1);
            }
            pre[a[vis[j]]]=j;
            add_t(j,1);
            j+=1;
        }
        ans[que[i].ind]=ask_t(que[i].r)-ask_t(que[i].l-1);
    }

 

 

2、求区间内独有颜色的数目? 

(1)首先预处理出来,每个颜色 最左L[i]最右R[i]

(2)每一个子树相当于一个区间询问,那么对于这些询问对有锻炼que[i].r进行排序(升)

(3)没到一个R[i],就就在树状数组中插入让的L[i],我们每一个询问问的  大于等于que[i].l的点有多少个、

 

主席树代码

#include <bits/stdc++.h>
#define  en '\n'
#define Swt  signed main
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
const int maxm=(1e5+10)*77;
int tot;
struct node{
int v,nxt,w;
}edge[maxn<<1];
int rd(){int tem;scanf("%d",&tem);return tem;}
int head[maxn];
void add(int x,int y,int w){edge[++tot]=(node){y,head[x],w};head[x]=tot;}
int col[maxn],dfn,in_ind[maxn],out_ind[maxn],in_edge[maxn],col_sum[maxn],c[maxn],vis[maxn],a[maxn];
int R[maxn],L[maxn],pre[maxn];
int col_have[maxn],rt[maxn];
int sm[maxm],ls[maxm],rs[maxm];
void dfs(int x,int f,int from){
    in_ind[x]=++dfn;
    vis[dfn]=x;
    in_edge[x]=from;
    for(int i=head[x];i;i=edge[i].nxt){
        int y=edge[i].v;if(y==f)continue;
        dfs(y,x,edge[i].w);
    }
    out_ind[x]=dfn;
}
void update(int &x,int y,int l,int r,int pos){
    x=++tot;
    sm[x]=sm[y];ls[x]=ls[y],rs[x]=rs[y];
    sm[x]+=1;
    if(l==r)return ;
    int mid=(l+r)>>1;
    if(pos<=mid)update(ls[x],ls[y],l,mid,pos);
    else        update(rs[x],rs[y],mid+1,r,pos);
}
int ask(int x,int y,int l,int r,int ql,int qr){
    if(ql<=l and r<=qr)return sm[y]-sm[x];
    int mid=(l+r)>>1;
    int tem=0;
    if(ql<=mid)tem+=ask(ls[x],ls[y],l,mid,ql,qr);
    if(qr>mid)tem+=ask(rs[x],rs[y],mid+1,r,ql,qr);
    return tem;
}
#define lowbit(x) (x&(-x))
void add_t(int x,int val){
    for(;x<maxn-1;x+=lowbit(x)){
        c[x]+=val;
    }
}
int ask_t(int x){int res=0; for(;x;x-=lowbit(x))res+=c[x];    return res;}
int que[maxn];
void dfs_2(int x,int f){
    if(R[a[x]]==in_ind[x]){
        add_t(L[a[x]],1);
    }
    for(int i=head[x];i;i=edge[i].nxt){
        int y=edge[i].v;if(y==f)continue;
        dfs_2(y,x);
    }
    col_have[x]-=ask_t(maxn-3)-ask_t(in_ind[x]-1);
    //cout<<x<<' '<<col_have[x]<<en;
    que[in_edge[x]]=col_have[x];
}
Swt(){
    #ifdef local
    freopen("input2.txt","r",stdin);
    #endif // local
    int n=rd();
    for(int i=1;i<=n;i++){a[i]=rd();col_sum[a[i]]+=1;}
    for(int i=1;i<n;i++){int x=rd(),y=rd();add(x,y,i);add(y,x,i);}
    dfs(1,0,0);
    for(int i=1;i<=n;i++){/// i is dfs_index
        int ind=vis[i];
        pre[i]=col[a[ind]];col[a[ind]]=i;
        if(L[a[ind]]==0)L[a[ind]]=i;
        R[a[ind]]=i;
    }
    for(int i=1;i<=n;i++){update(rt[i],rt[i-1],0,n,pre[i]);}
    for(int i=1;i<=n;i++){
        col_have[i]=ask(rt[in_ind[i]-1],rt[out_ind[i]],0,n,0,in_ind[i]-1);
    }
    dfs_2(1,0);
    for(int i=1;i<n;i++){
        cout<<que[i]<<'\n';
    }
    return 0;
}

两个树状数组代码

#include <bits/stdc++.h>
#define  en '\n'
#define pb push_back
using namespace std;
typedef long long ll;
const int maxn=1e5+10;
int tot;
struct node{
int v,nxt,w;
}edge[maxn<<1];
int rd(){int tem;scanf("%d",&tem);return tem;}
int head[maxn];
void add(int x,int y,int w){edge[++tot]=(node){y,head[x],w};head[x]=tot;}
int dfn,in_ind[maxn],out_ind[maxn],c[maxn],c2[maxn],vis[maxn],a[maxn];
int R[maxn],L[maxn],pre[maxn],ans[maxn];
struct nodee{
    int l,r,ind;
}que[maxn];
void dfs(int x,int f,int from){
    in_ind[x]=++dfn;
    if(!L[a[x]])L[a[x]]=dfn;
    R[a[x]]=dfn;
    que[from].l=dfn;
    vis[dfn]=x;
    for(int i=head[x];i;i=edge[i].nxt){
        int y=edge[i].v;if(y==f)continue;
        dfs(y,x,edge[i].w);
    }
 
    out_ind[x]=dfn;
    que[from].r=dfn;
}
#define lowbit(x) (x&(-x))
 
void add_t2(int x,int val){
    x+=1;
    for(;x<maxn-1;x+=lowbit(x)){
        c2[x]+=val;
    }
}
int ask_t2(int x){
    x+=1;
    int res=0;
    for(;x;x-=lowbit(x)){
        res+=c2[x];
    }return res;
}
void add_t(int x,int val){
    for(;x<maxn-1;x+=lowbit(x)){
        c[x]+=val;
    }
}
int ask_t(int x){int res=0; for(;x;x-=lowbit(x))res+=c[x];return res;}
void dfs_2(int x,int f,int from){
    if(R[a[x]]==in_ind[x]){
        add_t2(L[a[x]],1);
    }
    for(int i=head[x];i;i=edge[i].nxt){
        int y=edge[i].v;if(y==f)continue;
        dfs_2(y,x,edge[i].w);
    }
    ans[from]-=ask_t2(maxn-3)-ask_t2(in_ind[x]-1);
}
bool cmp(nodee a,nodee b){
    return a.r<b.r;
}
signed main(){
    #ifdef local
    freopen("input2.txt","r",stdin);
    #endif // local
    int n=rd();
 
    for(int i=1;i<=n;i++){a[i]=rd();}
    for(int i=1;i<=n;i++)que[i].ind=i;
    for(int i=1;i<n;i++){int x=rd(),y=rd();add(x,y,i);add(y,x,i);}
    dfs(1,0,0);
    //cout<<'s';return 0;
    sort(que+1,que+n,cmp);
 
  //  cout<<'s';return 0;
    for(int i=1,j=1;i<n;i++){
        while(j<=que[i].r){
            if(pre[a[vis[j]]]){
                add_t(pre[a[vis[j]]],-1);
            }
            pre[a[vis[j]]]=j;
            add_t(j,1);
            j+=1;
        }
        ans[que[i].ind]=ask_t(que[i].r)-ask_t(que[i].l-1);
    }
//cout<<'s';return 0;
 
    dfs_2(1,0,0);
    for(int i=1;i<n;i++){
        cout<<ans[i]<<en;
    }
    return 0;
}

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值