题目
题解
tarjan+dfs序+分块+莫队
首先用tarjan求出所有的环根,做个dfs,就可以统计出每个节点在不挑剔的情况下的值了。其实我并不懂怎么是怎么实现的最后可以做到x~x+son[x]-1(dfs序)都是在封路后可以到达的节点。
接下来用dfs序,可以把树给展开,方便统计子树的情况。
再接着就用莫队来控制区间,用分块来求出小于一定值的点有多少个。
最后输出答案。
整体思路是这样的,细节上要注意我们一共分了两次块,一次在莫队,一次是真的分块。
真的分块求的时候按油腻程度分成几大块,块外暴力求和,块内逐一判断。
代码
不要抄代码,要不你会后悔一辈子的!
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN=100010,MAXM=150010,MAXQ=100010,MAXA=1000010;
inline void read(int &x)
{
x=0;char ch=getchar();
while(ch<'0' || ch>'9') ch=getchar();
while(ch>='0' && ch<='9') x=x*10+(ch^48),ch=getchar();
}
inline void write(int x)
{
if(x>=10) write(x/10);
putchar(x%10|48);
}
int n,m,Q,sz1,sz2;
int o[MAXN],bl[MAXN];
struct Que{int l,r,x,opt,id;}q[MAXQ];
bool cmp(Que q1,Que q2)
{
if(bl[q1.l]!=bl[q2.l]) return bl[q1.l]<bl[q2.l];
return q1.r<q2.r;//debug bl[q1.r]<bl[q2.r];
}
struct E{int y,next;}e[MAXM*2];int len=1,last[MAXN];
void ins(int x,int y)
{
e[++len]=(E){y,last[x]};last[x]=len;
}
int dfs_colck=0,dfn[MAXN],low[MAXN],ys[MAXN];
void tarjan(int x,int fa)
{
dfn[x]=low[x]=++dfs_colck;
ys[dfs_colck]=x;
for(int k=last[x];k;k=e[k].next)
{
int y=e[k].y;
if(y==fa) continue;
if(!dfn[y]) tarjan(y,x),low[x]=min(low[x],low[y]);
else low[x]=min(low[x],dfn[y]);
}
}
bool vis[MAXN];
int tot=0,id[MAXN],son[MAXN];
void dfs(int x)
{
vis[x]=true;
id[x]=++tot;
son[x]=1;
for(int k=last[x];k;k=e[k].next)
{
int y=e[k].y;
if(vis[y] || dfn[x]>low[y]) continue;//不在环中 debug dfn[x]>low[y]
dfs(y);
son[x]+=son[y];
}
for(int k=last[x];k;k=e[k].next)
{
int y=e[k].y;
if(vis[y]) continue;//if(dfn[x]<=low[y]) 在环上
dfs(y);
son[ys[low[y]]]+=son[y];//debug son[ys[low[x]]]+=low[y];
}
}
int oil[MAXN];
int sum[2][MAXN],cnt[MAXA];
void update(int x,bool flag)
{
int val=oil[x],p=(val-1)/sz2+1;//debug p=(x-1)/sz2+1
if(flag)
{
if(!cnt[val]) sum[1][p]++;
else if(cnt[val]&1) sum[1][p]--,sum[0][p]++;
else sum[0][p]--,sum[1][p]++;
cnt[val]++;
}
else
{
if(cnt[val]==1) sum[1][p]--;
else if(cnt[val]&1) sum[1][p]--,sum[0][p]++;
else sum[0][p]--,sum[1][p]++;
cnt[val]--;
}
}
int calc(int x,int opt)
{
int re=0,p=(x-1)/sz2+1;
for(int i=1;i<p;i++) re+=sum[opt][i];
for(int i=(p-1)*sz2+1;i<=x;i++) re+=cnt[i]&&(cnt[i]&1)==opt;
return re;
}
int ans[MAXQ];
int main()
{
read(n),read(m);
sz1=sqrt(n);
for(int i=1;i<=sz1;i++) bl[i]=(i-1)/sz1+1;
for(int i=1;i<=n;i++) read(o[i]),sz2=max(sz2,o[i]);
sz2=sqrt(sz2);
for(int i=1;i<=m;i++)
{
int x,y;
read(x),read(y);
ins(x,y);ins(y,x);
}
tarjan(1,0);
dfs(1);
for(int i=1;i<=n;i++) oil[id[i]]=o[i];
read(Q);
for(int i=1;i<=Q;i++)
{
int x;
read(q[i].opt),read(x),read(q[i].x);
q[i].l=id[x];q[i].r=id[x]+son[x]-1;
q[i].id=i;
}
sort(q+1,q+Q+1,cmp);
int l=1,r=0;
for(int i=1;i<=Q;i++)
{
while(q[i].l<l) update(--l,1);//增
while(q[i].l>l) update(l++,0);//减
while(q[i].r<r) update(r--,0);//减
while(q[i].r>r) update(++r,1);//增
ans[q[i].id]=calc(q[i].x,q[i].opt);
}
for(int i=1;i<=Q;i++) write(ans[i]),putchar('\n');
return 0;
}