题意
做法
看到还有莫队+分块的神仙,反正我是没有想到的,没想到子树信息还能化成莫队???
首先,这道题目明摆着仙人掌,然后处理子树信息线段树合并即可。
这篇博客主要是记载我这另类的线段树合并的。
这道题目的线段树合并比较奇怪,因为子树信息是可以重合的,甚至还不满足可加性。。。
但是如果你能理解主席树的时间复杂度,你就可以知道这个并不是什么大问题。
时间复杂度:(O((n+q)logn))
空间复杂度:(O(nlog值域))
#include<cstdio>
#include<cstring>
#define N 110000
#define NN 210000
#define SN 6100000
#define M 320000
using namespace std;
inline int mymin(int x,int y){return x<y?x:y;}
inline int mymax(int x,int y){return x>y?x:y;}
class EDGE
{
public:
struct node
{
int y,next;
}a[M];int len,last[NN];
void ins(int x,int y){len++;a[len].y=y;a[len].next=last[x];last[x]=len;}
}a1,a2;
struct node
{
int l,r,c1/*奇数次*/,c2/*偶数次*/;
bool bk;//我的儿子是否是复制别人的
}tr[SN];int len,rt[NN];
inline void updata(int x){tr[x].c1=tr[tr[x].l].c1+tr[tr[x].r].c1;tr[x].c2=tr[tr[x].l].c2+tr[tr[x].r].c2;}
void link(int &x,int l,int r,int k)
{
if(l==r)
{
if(!x)x=++len,tr[x].c1=1;
else if(tr[x].c1)tr[x].c1=0,tr[x].c2=1;
else tr[x].c1=1,tr[x].c2=0;
return ;
}
if(!x)x=++len;
int mid=(l+r)>>1;
if(k<=mid)link(tr[x].l,l,mid,k);
else link(tr[x].r,mid+1,r,k);
updata(x);
}
void merge(int &x,int &y,int l,int r,int dep)//另类合并
{
if(!y)return ;
else if(!x)
{
x=++len;
tr[x]=tr[y];
tr[x].bk=1;//直接等于y,但是修改不能直接修改,会改变子树的信息
return ;
}
if(l==r)
{
int tx=0,ty=0;
if(tr[x].c1==1)tx=1;
if(tr[y].c1==1)ty=1;
if((tx+ty)&1)tr[x].c1=1,tr[x].c2=0;
else tr[x].c2=1,tr[x].c1=0;
return ;
}
if(tr[x].bk==1)//不难证明,这样子产生的点数为nlogn
{
int lc=0,rc=0;
if(tr[x].l)tr[lc=++len]=tr[tr[x].l],tr[lc].bk=1;
if(tr[x].r)tr[rc=++len]=tr[tr[x].r],tr[rc].bk=1;
//之前我直接创两个儿子节点是不行的,因为这样原本为空的儿子节点就变成可实实在在的儿子节点了。
tr[x].l=lc;tr[x].r=rc;
tr[x].bk=0;
}
int mid=(l+r)>>1;
merge(tr[x].l,tr[y].l,l,mid,dep+1);merge(tr[x].r,tr[y].r,mid+1,r,dep+1);
updata(x);
}
int findans(int x,int l,int r,int k,int type)
{
if(!x)return 0;
if(r<=k)return type==0?tr[x].c2:tr[x].c1;
int mid=(l+r)>>1;
if(mid>=k)return findans(tr[x].l,l,mid,k,type);
else return findans(tr[x].l,l,mid,k,type)+findans(tr[x].r,mid+1,r,k,type);
}
int dfn[N],low[N],sta[N],top,cnt,n,m,ti;
void dfs1(int x)
{
sta[++top]=x;dfn[x]=low[x]=++ti;
for(int k=a1.last[x];k;k=a1.a[k].next)
{
int y=a1.a[k].y;
if(!dfn[y])
{
dfs1(y);
low[x]=mymin(low[y],low[x]);
if(low[y]==dfn[x])
{
cnt++;
while(sta[top]!=y)a2.ins(n+cnt,sta[top--]);
a2.ins(n+cnt,sta[top--]);
a2.ins(x,n+cnt);
}
}
else low[x]=mymin(low[x],dfn[y]);
}
}
int fa[NN],val[N];
void dfs2(int x)
{
if(x<=n)link(rt[x],1,val[0],val[x]);
for(int k=a2.last[x];k;k=a2.a[k].next)
{
int y=a2.a[k].y;
if(y!=fa[x])
{
fa[y]=x;
dfs2(y);
merge(rt[x],rt[y],1,val[0],0);
}
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){scanf("%d",&val[i]);val[0]=mymax(val[i],val[0]);}
for(int i=1;i<=m;i++)
{
int x,y;scanf("%d%d",&x,&y);
a1.ins(x,y);a1.ins(y,x);
}
dfs1(1);
dfs2(1);
int q;scanf("%d",&q);
for(int i=1;i<=q;i++)
{
int id,type,limit;scanf("%d%d%d",&type,&id,&limit);
printf("%d
",findans(rt[id],1,val[0],limit,type));
}
return 0;
}