码迷,mamicode.com
首页 > 其他好文 > 详细

SP10707 COT2 - Count on a tree II 莫队上树

时间:2019-11-23 21:47:05      阅读:74      评论:0      收藏:0      [点我收藏+]

标签:hat   颜色   dig   getchar   sig   sizeof   ack   image   memcpy   

题意:求一条链 \((u,v)\) 上不同的颜色数。

我们可以求出树的出栈入栈序(or 括号序?我也不确定)。

图(from attack
技术图片

然后有一个很优美的性质:
设点 \(u\) 的入栈时间为 \(dfn[u]\) ,出栈时间为 \(low[u]\)
设两个点 \(u,v\) 满足 \(dfn[u]<dfn[v]\)
\(u\)\(v\)\(lca\),那么我们只需查询 \([dfn[u],dfn[v]]\)只出现一次的点有多少不同的颜色。
\(u\) , \(v\) 不在一个子树中,我们只需查询 \([low[u],dfn[v]]\)只出现一次的点有多少不同的颜色,并单独检查 \(lca\) 的颜色。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<vector>
#define R register int
using namespace std;
namespace Luitaryi {
inline int g() { R x=0,f=1;
    register char s; while(!isdigit(s=getchar())) f=s=='-'?-1:f;
    do x=x*10+(s^48); while(isdigit(s=getchar())); return x*f;
} const int N=200010,M=200010; bool vis[N];
int n,m,B,cnt,num,mem[N<<1],pos[N<<1],a[N],b[N],c[N],ans[N],tot;
int vr[N<<1],nxt[N<<1],fir[N],dfn[N],low[N],pre[N],top[N],sz[N],son[N],d[N];
inline void add(int u,int v) {
    vr[++cnt]=v,nxt[cnt]=fir[u],fir[u]=cnt;
    vr[++cnt]=u,nxt[cnt]=fir[v],fir[v]=cnt;
}
inline void dfs(int u) { sz[u]=1,dfn[u]=++num,mem[num]=u;
    for(R i=fir[u];i;i=nxt[i]) { R v=vr[i];
        if(d[v]) continue; pre[v]=u,d[v]=d[u]+1,dfs(v);
        if(sz[son[u]]<sz[v]) son[u]=v; sz[u]+=sz[v];
    } low[u]=++num,mem[num]=u;
}
inline void dfs2(int u,int tp) { top[u]=tp;
    if(son[u]) dfs2(son[u],tp);
    for(R i=fir[u];i;i=nxt[i]) { R v=vr[i];
        if(v!=son[u]&&v!=pre[u]) dfs2(v,v);
    }   
}
inline int lca(int u,int v) {
    for(;top[u]!=top[v];u=pre[top[u]]) if(d[top[u]]<d[top[v]]) swap(u,v);
    return d[u]<d[v]?u:v;
}
struct node {int l,r,op,id;
    inline bool operator < (const node& that) const 
        {return pos[l]==pos[that.l]?(pos[l]&1)?r<that.r:r>that.r:l<that.l;}
}q[M];
inline void add(int x) {if(++c[x]==1) ++tot;}
inline void sub(int x) {if(--c[x]==0) --tot;}
inline void f(int u) {vis[u]?sub(a[u]):add(a[u]); vis[u]^=1;}
inline void main() {
    n=g(),m=g(); B=sqrt(n);
    for(R i=1;i<=n;++i) a[i]=g();
    memcpy(b,a,sizeof b);
    sort(b+1,b+n+1); R t=unique(b+1,b+n+1)-b-1;
    for(R i=1;i<=n;++i) a[i]=lower_bound(b+1,b+t+1,a[i])-b;
    for(R i=1,u,v;i<n;++i) u=g(),v=g(),add(u,v); d[1]=1,dfs(1),dfs2(1,1);
    for(R i=1,u,v,l;i<=m;++i) {
        u=g(),v=g(),l=lca(u,v);
        if(dfn[u]>dfn[v]) swap(u,v);
        if(l==u) q[i]=(node){dfn[u],dfn[v],0,i};
        else q[i]=(node){low[u],dfn[v],l,i};
    } for(R i=1;i<=2*n;++i) pos[i]=(i-1)/B+1;
    sort(q+1,q+m+1);
    for(R i=1,l=1,r=0,op,LL,RR,id;i<=m;++i) {
        LL=q[i].l,RR=q[i].r,op=q[i].op,id=q[i].id;
        while(l<LL) f(mem[l++]);
        while(l>LL) f(mem[--l]);
        while(r<RR) f(mem[++r]);
        while(r>RR) f(mem[r--]);
        ans[id]=tot+(op&&c[a[op]]==0);
    } for(R i=1;i<=m;++i) printf("%d\n",ans[i]);
}
} signed main() {Luitaryi::main(); return 0;}

2019.11.21

SP10707 COT2 - Count on a tree II 莫队上树

标签:hat   颜色   dig   getchar   sig   sizeof   ack   image   memcpy   

原文地址:https://www.cnblogs.com/Jackpei/p/11919731.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!