仙人掌转成序列,然后莫队
仙人掌转成序列的方法是先tarjan找环,对于一个环上的点,如果是环根,那么这个环都属于其子仙人掌,如果不是环根,那么除了他自己这个环上都不是其子仙人掌,这样再dfs一次,对于一个点,优先走其出边里是其子仙人掌的部分,同时对于一个环,把不与环根相连的点的siz加到环根的siz里,这样仙人掌就转成了序列,一个子仙人掌对应的区间就是dfn[x]~dfn[x]+siz[x]-1
之后直接上莫队,用数据结构维护的话是n sqrtn logn的,T到爆,用和GTY的二逼妹子序列相同的方法,对权值分块,维护每块和每个点对答案的贡献,修改是单点修改,这样修改其所在块和这个位置,询问的时候变成sqrtn即可
数据好水啊,我在第二次dfs判这条出边和x是不是在一个环的时候没用tarjan的dfn而用了新dfs序都过了-_-
人生中第一次在BZOJ首A-_-
#include<iostream> #include<cstdlib> #include<cstdio> #include<cstring> #include<cmath> #include<ctime> #include<algorithm> #include<iomanip> #include<vector> #include<stack> #include<queue> #include<map> #include<set> #include<bitset> using namespace std; #define MAXN 100010 #define MAXM 300010 #define MAXC 1000010 #define ll long long #define INF 1000000000 #define MOD 1000000007 #define eps 1e-8 struct vec{ int to; int fro; }; struct que{ int cl; int v; int l; int r; int k; int num; friend bool operator <(que x,que y){ return x.k!=y.k?x.k<y.k:x.r<y.r; } }; int A[MAXN],a[MAXN]; int c; que q[MAXN]; vec mp[MAXM]; int tai[MAXN],cnt=1; int dfn[MAXN],DFN[MAXN],low[MAXN],ndf[MAXN],tim; int n,m; int siz[MAXN]; int ANS[2][MAXC]; int CNT[MAXC]; int Asiz; int ans[MAXN]; inline void be(int x,int y){ mp[++cnt].to=y; mp[cnt].fro=tai[x]; tai[x]=cnt; } inline void bde(int x,int y){ be(x,y); be(y,x); } void dfs(int x,int f){ int i,y; DFN[x]=low[x]=++tim; ndf[tim]=x; for(i=tai[x];i;i=mp[i].fro){ y=mp[i].to; if(i==(f^1)){ continue ; } if(!DFN[y]){ dfs(y,i); low[x]=min(low[x],low[y]); }else{ low[x]=min(low[x],DFN[y]); } } } void dfs2(int x,int f){ int i,y; siz[x]=1; dfn[x]=++tim; for(i=tai[x];i;i=mp[i].fro){ y=mp[i].to; if(i==(f^1)){ continue ; } if(!dfn[y]&&low[y]>=dfn[x]){ dfs2(y,i); if(low[y]>dfn[x]){ siz[x]+=siz[y]; } } } for(i=tai[x];i;i=mp[i].fro){ y=mp[i].to; if(i==(f^1)){ continue ; } if(!dfn[y]&&low[y]<dfn[x]){ dfs2(y,i); } } if(low[x]!=DFN[x]){ siz[ndf[low[x]]]+=siz[x]; } } int main(){ int i,j,o,x,y; scanf("%d%d",&n,&m); for(i=1;i<=n;i++){ scanf("%d",&A[i]); c=max(c,A[i]); } Asiz=sqrt(c); for(i=1;i<=m;i++){ scanf("%d%d",&x,&y); bde(x,y); } dfs(1,0); tim=0; dfs2(1,0); for(i=1;i<=n;i++){ a[dfn[i]]=A[i]; } /* for(i=1;i<=n;i++){ //<<DFN[i]<<' '<<low[i]<<endl; } for(i=1;i<=n;i++){ //<<i<<'!'<<dfn[i]<<' '<<siz[i]<<endl; } //*/ scanf("%d",&m); int SIZ=sqrt(n); for(i=1;i<=m;i++){ scanf("%d%d%d",&q[i].cl,&q[i].l,&q[i].v); q[i].r=dfn[q[i].l]+siz[q[i].l]-1; q[i].l=dfn[q[i].l]; q[i].k=q[i].l/SIZ; q[i].num=i; } sort(q+1,q+m+1); int L=1,R=0; /* for(i=1;i<=n;i++){ //<<a[i]<<' '; } //<<endl; */ for(i=1;i<=m;i++){ while(L>q[i].l){ L--; //<<a[L]<<endl; x=(a[L]-1)/Asiz+1; if(CNT[a[L]]){ ANS[CNT[a[L]]&1][x]--; } CNT[a[L]]++; ANS[CNT[a[L]]&1][x]++; } while(R<q[i].r){ R++; x=(a[R]-1)/Asiz+1; //<<a[R]<<endl; if(CNT[a[R]]){ ANS[CNT[a[R]]&1][x]--; } CNT[a[R]]++; ANS[CNT[a[R]]&1][x]++; } while(L<q[i].l){ //<<a[L]<<endl; x=(a[L]-1)/Asiz+1; ANS[CNT[a[L]]&1][x]--; CNT[a[L]]--; if(CNT[a[L]]){ ANS[CNT[a[L]]&1][x]++; } L++; } while(R>q[i].r){ x=(a[R]-1)/Asiz+1; //<<a[R]<<endl; ANS[CNT[a[R]]&1][x]--; CNT[a[R]]--; if(CNT[a[R]]){ ANS[CNT[a[R]]&1][x]++; } R--; } /* //<<L<<' '<<R<<endl; for(j=1;j<=(c-1)/Asiz+1;j++){ //<<ANS[0][j]<<'!'; } //<<endl; for(j=1;j<=(c-1)/Asiz+1;j++){ //<<ANS[1][j]<<'!'; } //<<endl; */ x=(q[i].v-1)/Asiz+1; for(j=1;j<x;j++){ ans[q[i].num]+=ANS[q[i].cl][j]; } for(j=(x-1)*Asiz+1;j<=q[i].v;j++){ if(CNT[j]&&((CNT[j]&1)==q[i].cl)){ ans[q[i].num]++; } } } for(i=1;i<=m;i++){ printf("%d\n",ans[i]); } return 0; } /* 7 8 1 2 2 3 3 4 4 1 3 5 5 6 6 7 7 3 5 6 2 1 6 7 7 1 2 1 3 2 4 4 5 4 5 1 3 3 0 3 2 0 3 1 0 1 7 */</span>