Description
Rin是个特别好动的少女。
一天Rin来到了一个遥远的都市。这个都市有N个建筑,编号从1到N,其中市中心编号为1,这个都市有M条双向通行的街道,每条街道连接着两个不同的建筑,其中某些街道首尾相连连接成了一个环。Rin通过长时间的走访,已经清楚了这个都市的两个特点:
从市中心出发可以到达所有的建筑物。
任意一条街道最多存在与一个简单环中。令Rin心花怒放的是,每个建筑物都会有拉面售卖。拉面有很多不同的种类,但对于Rin而言只有油腻程度的不同,因此我们把油腻程度相同的拉面看做同一种拉面。由于不同建筑物的拉面的油腻程度可能不同,我们用一个正整数来表示拉面的油腻程度。
要知道,拉面可是Rin的最爱,但是现在到了下班高峰期,都市的交通变得非常的堵塞。Rin只能通过没有被堵死的街道通行,去品尝所在建筑物的拉面。
现在Rin想知道,如果她正在编号为x的建筑物,那么在从市中心到x的所有简单路径经过的街道都被堵死的情况下,Rin可以品尝到的拉面中(注意没有出现的拉面是不能算在里面的):
油腻程度<=y且品尝次数为奇数次的拉面有多少种?
油腻程度<=y且品尝次数为偶数次的拉面有多少种?
n<=100000,询问次数<=100000,边数<=150000,颜色<=1e6
Solution
似乎要各种缩点判环??
并不需要
从1开始DFS,将一个环上深度最小的点设为这个环的环顶,将环上原来的边删掉,环上每个点向环顶连边,其他边不变
那么这就变成一棵树了,可以发现这样变了以后询问就变成一棵树上的子树询问了
离线把询问挂在点上从底向上进行线段树合并即可
Code
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstdlib>
#include <cstring>
#include <cmath>
#include <vector>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fod(i,a,b) for(int i=a;i>=b;i--)
#define N 100005
#define M 650005
using namespace std;
bool bz[M],b2[M];
int fs[N],dep[N],m1,nt[M],dt[M],pr[N],n,m,rt[N],even[50*N],odd[50*N],n1,ask[N][4],st[N][2],top,mx,fx[M],ct[50*N];
vector<int> vis[N];
struct node
{
int l,r;
}tr[50*N];
void link(int x,int y)
{
nt[++m1]=fs[x];
dt[fs[x]=m1]=y;
}
void visit(int k,int f)
{
int t=top;
while(t&&st[t][0]!=f) link(f,st[t][0]),link(st[t][0],f),b2[fx[m1]=m1-1]=b2[fx[m1-1]=m1]=1,bz[st[t][1]]=bz[fx[st[t][1]]]=1,t--;
}
void make(int k,int fa,int fn)
{
dep[k]=dep[fa]+1;
st[++top][0]=k,st[top][1]=fn;
for(int i=fs[k];i;i=nt[i])
{
int p=dt[i];
if(b2[i]) continue;
if(i==fx[fn]) continue;
if(dep[p]<dep[k]&&dep[p]) visit(k,p),bz[i]=bz[fx[i]]=1;
else if(!dep[p]) make(p,k,i);
}
st[top][0]=0,st[top--][1]=0;
}
void up(int k)
{
ct[k]=ct[tr[k].l]+ct[tr[k].r];
odd[k]=odd[tr[k].l]+odd[tr[k].r];
even[k]=even[tr[k].l]+even[tr[k].r];
}
void ins(int k,int l,int r,int w)
{
if(l==r&&l==w)
{
ct[k]++;
odd[k]=(ct[k]&1),even[k]=1-odd[k];
return;
}
int mid=(l+r)/2;
if(tr[k].l==0) tr[k].l=++n1,tr[k].r=++n1;
if(w<=mid) ins(tr[k].l,l,mid,w);
else ins(tr[k].r,mid+1,r,w);
up(k);
}
int hb(int k,int p,int l,int r)
{
if(p==0) return k;
if(k==0) return p;
if(l==r)
{
ct[k]+=ct[p];
if(ct[k]!=0) odd[k]=(ct[k]&1),even[k]=1-odd[k];
return k;
}
int mid=(l+r)/2;
tr[k].l=hb(tr[k].l,tr[p].l,l,mid);
tr[k].r=hb(tr[k].r,tr[p].r,mid+1,r);
up(k);
}
int get(int k,int l,int r,int x,int y,int v)
{
x=max(x,l),y=min(y,r);
if(x>y||!k) return 0;
if(l==x&&r==y) return(v)?odd[k]:even[k];
int mid=(l+r)/2;
return get(tr[k].l,l,mid,x,y,v)+get(tr[k].r,mid+1,r,x,y,v);
}
void dfs(int k,int fa)
{
rt[k]=++n1;
for(int i=fs[k];i;i=nt[i])
{
int p=dt[i];
if(p!=fa&&!bz[i]) dfs(p,k),hb(rt[k],rt[p],0,mx);
}
ins(rt[k],0,mx,pr[k]);
for(vector<int>::iterator i=vis[k].begin();i!=vis[k].end();++i)
{
ask[*i][3]=get(rt[k],0,mx,0,ask[*i][2],ask[*i][0]);
}
}
int main()
{
cin>>n>>m;
fo(i,1,n) scanf("%d",&pr[i]),mx=max(mx,pr[i]);
fo(i,1,m)
{
int x,y;
scanf("%d%d",&x,&y);
link(x,y);
link(y,x);
fx[m1]=m1-1,fx[m1-1]=m1;
}
make(1,0,0);
int q;
cin>>q;
fo(i,1,q)
{
fo(j,0,2) scanf("%d",&ask[i][j]);
vis[ask[i][1]].push_back(i);
}
dfs(1,0);
fo(i,1,q) printf("%d\n",ask[i][3]);
}