bzoj 4999 This Problem Is Too Simple!

题目大意:

给一颗树,每个节点有个初始值

现在支持以下两种操作:

1. C i x 表示将i节点的值改为x

2. Q i j x 表示询问i节点到j节点的路径上有多少个值为x的节点

思路:

首先可以想到树链剖分

虽然颜色的数量看起来很吓人

但是实际上只可能有n+q种颜色

所以我们的线段树只需要像主席树那样去写就可以了

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cmath>
  4 #include<cstdlib>
  5 #include<cstring>
  6 #include<algorithm>
  7 #include<vector>
  8 #include<queue>
  9 #include<map>
 10 #define inf 2139062143
 11 #define ll long long
 12 #define MAXN 100100
 13 using namespace std;
 14 inline int read()
 15 {
 16     int x=0,f=1;char ch=getchar();
 17     while(!isdigit(ch)) {if(ch==‘-‘) f=-1;ch=getchar();}
 18     while(isdigit(ch)) {x=x*10+ch-‘0‘;ch=getchar();}
 19     return x*f;
 20 }
 21 int n,T,val[MAXN],to[MAXN<<1],fst[MAXN],nxt[MAXN<<1],Cnt,cnt[MAXN],dep[MAXN],fa[MAXN],bl[MAXN],hsh[MAXN],rt[MAXN<<2],clr;
 22 map <int,int> m;
 23 struct data {int ls,rs,sum;}tr[MAXN<<7];
 24 void add(int u,int v) {nxt[++Cnt]=fst[u],fst[u]=Cnt,to[Cnt]=v;}
 25 void dfs(int x)
 26 {
 27     cnt[x]=1;
 28     for(int i=fst[x];i;i=nxt[i])
 29     {
 30         if(to[i]==fa[x]) continue;
 31         fa[to[i]]=x,dep[to[i]]=dep[x]+1;
 32         dfs(to[i]);
 33         cnt[x]+=cnt[to[i]];
 34     }
 35 }
 36 void Dfs(int x,int anc)
 37 {
 38     int hvs=0;hsh[x]=++Cnt,bl[x]=anc;
 39     for(int i=fst[x];i;i=nxt[i])
 40         if(to[i]!=fa[x]&&cnt[hvs]<cnt[to[i]]) hvs=to[i];
 41     if(!hvs) return ;
 42     Dfs(hvs,anc);
 43     for(int i=fst[x];i;i=nxt[i])
 44         if(to[i]!=fa[x]&&to[i]!=hvs) Dfs(to[i],to[i]);
 45 }
 46 void inst(int &k,int l,int r,int x,int w)
 47 {
 48     if(!k) k=++Cnt;
 49     tr[k].sum+=w;
 50     if(l==r) return;
 51     int mid=(l+r)>>1;
 52     if(x<=mid) inst(tr[k].ls,l,mid,x,w);
 53     else inst(tr[k].rs,mid+1,r,x,w);
 54 }
 55 int query(int k,int l,int r,int a,int b)
 56 {
 57     if(!k) return 0;
 58     if(a==l&&r==b) return tr[k].sum;
 59     int mid=(l+r)>>1;
 60     if(b<=mid) return query(tr[k].ls,l,mid,a,b);
 61     else if(a>mid) return query(tr[k].rs,mid+1,r,a,b);
 62     else return query(tr[k].ls,l,mid,a,mid)+query(tr[k].rs,mid+1,r,mid+1,b);
 63 }
 64 int main()
 65 {
 66     n=read(),T=read();int a,b,c,res;char ch[5];
 67     for(int i=1;i<=n;i++) val[i]=read();
 68     for(int i=1;i<n;i++) {a=read(),b=read();add(a,b);add(b,a);}
 69     dep[1]=1;
 70     dfs(1);Cnt=0;
 71     Dfs(1,1);Cnt=0;
 72     for(int i=1;i<=n;i++)
 73     {
 74         if(!m[val[i]]) m[val[i]]=++clr;
 75         inst(rt[m[val[i]]],1,n,hsh[i],1);
 76     }
 77     while(T--)
 78     {
 79         scanf("%s",ch);a=read(),b=read();
 80         if(ch[0]==‘C‘)
 81         {
 82             inst(rt[m[val[a]]],1,n,hsh[a],-1);
 83             if(!m[b]) m[b]=++clr;
 84             inst(rt[m[b]],1,n,hsh[a],1);
 85             val[a]=b;
 86         }
 87         else
 88         {
 89             c=read(),res=0;
 90             if(!m[c]) {puts("0");continue;}
 91             while(bl[a]!=bl[b])
 92             {
 93                 //cout<<a<<" "<<b<<" "<<res<<endl;
 94                 if(dep[bl[a]]<dep[bl[b]]) swap(a,b);
 95                 res+=query(rt[m[c]],1,n,hsh[bl[a]],hsh[a]);
 96                 a=fa[bl[a]];
 97             }
 98         //cout<<a<<" "<<b<<" "<<res<<endl;
 99             res+=query(rt[m[c]],1,n,min(hsh[a],hsh[b]),max(hsh[a],hsh[b]));
100             printf("%d\n",res);
101         }
102     }
103 }

原文地址:https://www.cnblogs.com/yyc-jack-0920/p/8468788.html

时间: 2024-10-13 01:56:46

bzoj 4999 This Problem Is Too Simple!的相关文章

[BZOJ 4999]This Problem Is Too Simple!

[BZOJ 4999]This Problem Is Too Simple! 题目 给您一颗树,每个节点有个初始值. 现在支持以下两种操作: 1. C i x(0<=x<2^31) 表示将i节点的值改为x. 2. Q i j x(0<=x<2^31) 表示询问i节点到j节点的路径上有多少个值为x的节点. INPUT 第一行有两个整数N,Q(1 ≤N≤ 100,000:1 ≤Q≤ 200,000),分别表示节点个数和操作个数. 下面一行N个整数,表示初始时每个节点的初始值. 接下来N

【BZOJ4999】This Problem Is Too Simple! 离线+树状数组+LCA

[BZOJ4999]This Problem Is Too Simple! Description 给您一颗树,每个节点有个初始值. 现在支持以下两种操作: 1. C i x(0<=x<2^31) 表示将i节点的值改为x. 2. Q i j x(0<=x<2^31) 表示询问i节点到j节点的路径上有多少个值为x的节点. Input 第一行有两个整数N,Q(1 ≤N≤ 100,000:1 ≤Q≤ 200,000),分别表示节点个数和操作个数. 下面一行N个整数,表示初始时每个节点的初

【bzoj4999】This Problem Is Too Simple! 树链剖分+动态开点线段树

题目描述 给您一颗树,每个节点有个初始值. 现在支持以下两种操作: 1. C i x(0<=x<2^31) 表示将i节点的值改为x. 2. Q i j x(0<=x<2^31) 表示询问i节点到j节点的路径上有多少个值为x的节点. 输入 第一行有两个整数N,Q(1 ≤N≤ 100,000:1 ≤Q≤ 200,000),分别表示节点个数和操作个数. 下面一行N个整数,表示初始时每个节点的初始值. 接下来N-1行,每行两个整数x,y,表示x节点与y节点之间有边直接相连(描述一颗树).

【BZOJ】【3489】A simple rmq problem

KD-Tree(乱搞) Orz zyf教给蒟蒻做法 蒟蒻并不会这题正解……(可持久化树套树?...Orz 对于每个点,我们可以求出pre[i],nex[i],那么询问的答案就是:求max (a[i]),其中 i 满足$ ( pre[i]<ql \ and \ nex[i]>qr\ and\ i \in [ql,qr] ) $ 然后我们以(i,pre[i],nex[i])为坐标……将所有点抽象到三维空间中,每次查询就相当于是一次区域求最值! 这题我的感受: 因为前面做了两道区域求和的……然后思路

BZOJ 2301: [HAOI2011]Problem b(莫比乌斯反演 + 容斥原理 + 分块优化)

传送门 Problem 2301. – [HAOI2011]Problem b 2301: [HAOI2011]Problem b Time Limit: 50 Sec  Memory Limit: 256 MBSubmit: 3671  Solved: 1643[Submit][Status][Discuss] Description 对于给出的n个询问,每次求有多少个数对(x,y),满足a≤x≤b,c≤y≤d,且gcd(x,y) = k,gcd(x,y)函数为x和y的最大公约数. Input

BZOJ 2302: [HAOI2011]Problem c( dp )

dp(i, j)表示从i~N中为j个人选定的方案数, 状态转移就考虑选多少人为i编号, 然后从i+1的方案数算过来就可以了. 时间复杂度O(TN^2) --------------------------------------------------------------------- #include<cstdio> #include<algorithm> #include<cstring> using namespace std; typedef long lo

[BZOJ 2301] [HAOI2011] Problem b

2301: [HAOI2011]Problem b Time Limit: 50 SecMemory Limit: 256 MB Description 对于给出的n个询问,每次求有多少个数对(x,y),满足a≤x≤b,c≤y≤d,且gcd(x,y) = k,gcd(x,y)函数为x和y的最大公约数. Input 第一行一个整数n,接下来n行每行五个整数,分别表示a.b.c.d.k Output 共n行,每行一个整数表示满足要求的数对(x,y)的个数 Sample Input 2 2 5 1 5

bzoj 2301: [HAOI2011]Problem b mobius反演 RE

http://www.lydsy.com/JudgeOnline/problem.php?id=2301 设f(i)为在区间[1, n]和区间[1, m]中,gcd(x, y) = i的个数. 设F(i)为在区间[1, n]和区间[1, m]中,gcd(x, y) % i == 0的个数,很简单的公式就是floor(n / i) * floor(m / i) 可知gcd(x, y) = k * i也属于F(i)的范围,所以可以反演得到f(i)的表达式. 算一次复杂度O(n),而且询问区间的时候要

BZOJ 2301([HAOI2011]Problem b-mobius反演)

2301: [HAOI2011]Problem b Time Limit: 50 Sec  Memory Limit: 256 MB Submit: 2170  Solved: 934 [Submit][Status][Discuss] Description 对于给出的n个询问,每次求有多少个数对(x,y),满足a≤x≤b,c≤y≤d,且gcd(x,y) = k,gcd(x,y)函数为x和y的最大公约数. Input 第一行一个整数n,接下来n行每行五个整数,分别表示a.b.c.d.k Out