给您一颗树,每个节点有个初始值。
现在支持以下两种操作:
1. C i x(0<=x<2^31) 表示将i节点的值改为x。
2. Q i j x(0<=x<2^31) 表示询问i节点到j节点的路径上有多少个值为x的节点。
鸣谢佚名上传
解题思路:正常做法为树链剖分+线段树,每个数字都建一棵线段树,但是这样会爆空间和时间,所以我们动态开点就好了。重新练习了一波动态开点建树。
#include
using namespace std;
typedef long long ll;
const int MAXN=100100;
struct Edge
{
int to;
int next;
}e[MAXN*2];
int head[MAXN],edge_num;
void insert_edge(int u,int v)
{
e[edge_num].to=v;
e[edge_num].next=head[u];
head[u]=edge_num++;
}
int top[MAXN];
int fa[MAXN];
int deep[MAXN];
int size[MAXN];
int son[MAXN];
int pos[MAXN];
int SEG;
int A[MAXN];
int N,Q;
void init(){
edge_num=0;
memset(head,-1,sizeof(head));
SEG=1;
memset(son,-1,sizeof(son));
}
void dfs1(int u,int pre,int d){
deep[u]=d;
fa[u]=pre;
size[u]=1;
for(int i=head[u];i!=-1;i=e[i].next){
int v=e[i].to;
if(v!=pre)
{
dfs1(v,u,d+1);
size[u]+=size[v];
if(son[u]==-1||size[v]>size[son[u]])
son[u]=v;
}
}
}
void dfs2(int u,int sp){
top[u]=sp;
pos[u]=SEG++;
if(son[u]!=-1)
dfs2(son[u],sp);
else
return;
for(int i=head[u];i!=-1;i=e[i].next){
int v=e[i].to;
if(v!=son[u]&&v!=fa[u])
dfs2(v,v);
}
}
int root[MAXN<<2],ls[MAXN<<7],rs[MAXN<<7],sum[MAXN<<7];
int col=0,tot=0;
void pushup(int rt){
sum[rt]=sum[ls[rt]]+sum[rs[rt]];
}
void update(int L,int C,int l,int r,int &rt){
if(!rt)
rt=++tot;
if(l==r){
sum[rt]+=C;
return;
}
int m=(l+r)/2;
if(L<=m)
update(L,C,l,m,ls[rt]);
else
update(L,C,m+1,r,rs[rt]);
pushup(rt);
}
int query(int L,int R,int l,int r,int rt){
if(!rt)
return 0;
if(L<=l&&r<=R)return sum[rt];
int m=(l+r)/2;
int ans=0;
if(L<=m)
ans+=query(L,R,l,m,ls[rt]);
if(R>m)
ans+=query(L,R,m+1,r,rs[rt]);
return ans;
}
int query(int u,int v,int x){
int f1=top[u],f2=top[v];
int temp=0;
while(f1!=f2){
if(deep[f1]deep[v])
swap(u,v);
temp+=query(pos[u],pos[v],1,N,root[x]);
return temp;
}
map mp;
int main(){
init();
scanf("%d%d",&N,&Q);
for(int i=1;i<=N;i++)
scanf("%d",&A[i]);
int x,y;
for(int i=0;i