BZOJ 4154

感觉这个题的思想还是很妙的,刚开始看这道题的时候大概会向一些树的算法比如树链剖分或是主席树维护深度之类的方向去想,但是我们考虑它实际上是一个二维数点的问题,由于是子树的修改,我们很自然的会想到用DFS序来搞,那么对于一个子树深度不超过定值的所有点就被包含在了一个矩形中,这样我们就可以用KD_tree来进行矩形的赋值,单点查询了,这个我不知道可不可以用树套树来做,如果哪位神犇会用树套树来搞的话,请留言指导一下蒟蒻。

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<algorithm>
  4 using namespace std;
  5 #define maxn 100005
  6 typedef long long LL;
  7 const int mo=1000000007;
  8 int pre[maxn],last[maxn],other[maxn];
  9 int st[maxn],en[maxn],dep[maxn];
 10 int n,m,q,l,T,tot,rt,cmp_d,now[2];
 11 LL ans;
 12 struct KD_tree
 13 {
 14     int ls,rs;
 15     int d[2],mn[2],mx[2];
 16     int col,lazy;
 17 }t[maxn];
 18
 19 inline int read(void)
 20 {
 21     int x=0;
 22     char ch=getchar();
 23     while (ch>‘9‘||ch<‘0‘) ch=getchar();
 24     while (ch>=‘0‘&&ch<=‘9‘)
 25     {
 26         x=x*10+ch-‘0‘;
 27         ch=getchar();
 28     }
 29     return x;
 30 }
 31
 32 void connect(int x,int y)
 33 {
 34     l++;
 35     pre[l]=last[x];
 36     last[x]=l;
 37     other[l]=y;
 38 }
 39
 40 void dfs(int u)
 41 {
 42     st[u]=++tot;
 43     for (int p=last[u];p;p=pre[p])
 44     {
 45         int v=other[p];
 46         dep[v]=dep[u]+1;
 47         dfs(v);
 48     }
 49     en[u]=tot;
 50 }
 51
 52 inline bool cmp(KD_tree a,KD_tree b)
 53 {
 54     int x=a.d[cmp_d],y=b.d[cmp_d];
 55     return x<y||(x==y&&a.d[!cmp_d]<b.d[!cmp_d]);
 56 }
 57
 58 void KD_update(int x)
 59 {
 60     int ls=t[x].ls;
 61     int rs=t[x].rs;
 62     if (ls)
 63     {
 64         t[x].mn[0]=min(t[x].mn[0],t[ls].mn[0]);
 65         t[x].mx[0]=max(t[x].mx[0],t[ls].mx[0]);
 66         t[x].mn[1]=min(t[x].mn[1],t[ls].mn[1]);
 67         t[x].mx[1]=max(t[x].mx[1],t[ls].mx[1]);
 68     }
 69     if (rs)
 70     {
 71         t[x].mn[0]=min(t[x].mn[0],t[rs].mn[0]);
 72         t[x].mx[0]=max(t[x].mx[0],t[rs].mx[0]);
 73         t[x].mn[1]=min(t[x].mn[1],t[rs].mn[1]);
 74         t[x].mx[1]=max(t[x].mx[1],t[rs].mx[1]);
 75     }
 76 }
 77
 78 int KD_build(int l,int r,int D)
 79 {
 80     int mid=(l+r)>>1;
 81     cmp_d=D;
 82     nth_element(t+l,t+mid,t+r+1,cmp);
 83     t[mid].mn[0]=t[mid].mx[0]=t[mid].d[0];
 84     t[mid].mn[1]=t[mid].mx[1]=t[mid].d[1];
 85     t[mid].col=1;t[mid].lazy=0;
 86     t[mid].ls=t[mid].rs=0;
 87     if (l<mid) t[mid].ls=KD_build(l,mid-1,D^1);
 88     if (r>mid) t[mid].rs=KD_build(mid+1,r,D^1);
 89     KD_update(mid);
 90     return mid;
 91 }
 92
 93 inline void push_down(int x)
 94 {
 95     if (!t[x].lazy) return;
 96     int ls=t[x].ls,rs=t[x].rs;
 97     if (ls) t[ls].col=t[ls].lazy=t[x].lazy;
 98     if (rs) t[rs].col=t[rs].lazy=t[x].lazy;
 99     t[x].lazy=0;
100 }
101
102 int KD_ask(int x,int D)
103 {
104     if (t[x].d[0]==now[0]&&t[x].d[1]==now[1]) return t[x].col;
105     push_down(x);
106     if (now[D]<t[x].d[D]||(now[D]==t[x].d[D]&&now[!D]<t[x].d[!D]))
107         return KD_ask(t[x].ls,D^1);
108     else
109         return KD_ask(t[x].rs,D^1);
110 }
111
112 inline pair<bool,bool> in(int x,int x1,int y1,int x2,int y2)
113 {
114     bool p1= t[x].mn[0]>=x1&&t[x].mx[0]<=x2&&t[x].mn[1]>=y1&&t[x].mx[1]<=y2;
115     bool p2= t[x].d[0]>=x1&&t[x].d[0]<=x2&&t[x].d[1]>=y1&&t[x].d[1]<=y2;
116     return make_pair(p1,p2);
117 }
118
119 inline bool out(int x,int x1,int y1,int x2,int y2)
120 {
121     return t[x].mx[0]<x1||t[x].mn[0]>x2||t[x].mx[1]<y1||t[x].mn[1]>y2;
122 }
123
124 void KD_add(int x,int x1,int y1,int x2,int y2,int c)
125 {
126     if (!x) return;
127     push_down(x);
128     if (in(x,x1,y1,x2,y2).first)
129     {
130         t[x].col=t[x].lazy=c;
131         return;
132     }
133     if (out(x,x1,y1,x2,y2)) return;
134     if (in(x,x1,y1,x2,y2).second) t[x].col=c;
135     KD_add(t[x].ls,x1,y1,x2,y2,c);
136     KD_add(t[x].rs,x1,y1,x2,y2,c);
137 }
138
139 int main()
140 {
141     T=read();
142     while (T--)
143     {
144         memset(last,0,sizeof last);l=tot=0;
145         n=read();m=read();q=read();
146         for (int i=2;i<=n;i++)
147         {
148             int fa=read();
149             connect(fa,i);
150         }
151         dfs(1);
152         for (int i=1;i<=n;i++) t[i].d[0]=st[i],t[i].d[1]=dep[i];
153         rt=KD_build(1,n,0);
154         ans=0;
155         for (int i=1;i<=q;i++)
156         {
157             int x=read(),y=read(),c=read();
158             if (c==0)
159             {
160                 now[0]=st[x];now[1]=dep[x];
161                 y=KD_ask(rt,0);
162                 ans=(ans+(LL)y*i)%mo;
163             }
164             else
165             {
166                 int x1=st[x],y1=dep[x];
167                 int x2=en[x],y2=dep[x]+y;
168                 KD_add(rt,x1,y1,x2,y2,c);
169             }
170         }
171         printf("%lld\n",ans);
172     }
173     return 0;
174 }
时间: 2024-10-28 10:10:41

BZOJ 4154的相关文章

BZOJ 4154 [Ipsc2015]Generating Synergy(KD-Tree)

题目链接:BZOJ 4154 [Ipsc2015]Generating Synergy 题意: 给定一棵以1为根的有根树,初始所有节点颜色为1,每次将距离节点a不超过l的a的子节点染成c,或询问点a的颜色. 题解: 将dfs序看为x,dep看为y,那么就是一个在二维平面上的操作了. 由于这个平面范围比较大,二维线段树不好开,然后kd-tree搞搞. 1 #include<cstdio> 2 #include<algorithm> 3 #define F(i,a,b) for(int

【BZOJ】【1007】【HNOI2008】水平可见直线

计算几何初步 其实是维护一个类似下凸壳的东西?画图后发现其实斜率是单调递增的,交点的横坐标也是单调递增的,所以排序一下搞个单调栈来做就可以了…… 看了hzwer的做法…… 1 /************************************************************** 2 Problem: 1007 3 User: Tunix 4 Language: C++ 5 Result: Accepted 6 Time:252 ms 7 Memory:2812 kb 8

BZOJ 1013: [JSOI2008]球形空间产生器sphere

二次联通门 : BZOJ 1013: [JSOI2008]球形空间产生器sphere /* BZOJ 1013: [JSOI2008]球形空间产生器sphere 高斯消元 QAQ SB的我也能终于能秒题了啊 设球心的坐标为(x,y,z...) 那么就可以列n+1个方程,化化式子高斯消元即可 */ #include <cstdio> #include <iostream> #include <cstring> #define rg register #define Max

bzoj 3309 DZY Loves Math - 莫比乌斯反演 - 线性筛

对于正整数n,定义f(n)为n所含质因子的最大幂指数.例如f(1960)=f(2^3 * 5^1 * 7^2)=3, f(10007)=1, f(1)=0. 给定正整数a,b,求sigma(sigma(f(gcd(i,j)))) (i=1..a, j=1..b). Input 第一行一个数T,表示询问数. 接下来T行,每行两个数a,b,表示一个询问. Output 对于每一个询问,输出一行一个非负整数作为回答. Sample Input 4 7558588 9653114 6514903 445

【BZOJ】[HNOI2009]有趣的数列

[算法]Catalan数 [题解] 学了卡特兰数就会啦>_<! 因为奇偶各自递增,所以确定了奇偶各自的数字后排列唯一. 那么就是给2n个数分奇偶了,是不是有点像入栈出栈序呢. 将做偶数标为-1,做奇数标为+1,显然当偶数多于奇数时不合法,因为它压不住后面的奇数. 然后其实这种题目,打表就可知啦--QAQ 然后问题就是求1/(n+1)*C(2n,n)%p了,p不一定是素数. 参考bzoj礼物的解法. 看到网上清一色的素数筛+分解质因数解法,不解了好久,感觉写了假的礼物-- 后来觉得礼物的做法才比

洛谷 P2709 BZOJ 3781 小B的询问

题目描述 小B有一个序列,包含N个1~K之间的整数.他一共有M个询问,每个询问给定一个区间[L..R],求Sigma(c(i)^2)的值,其中i的值从1到K,其中c(i)表示数字i在[L..R]中的重复次数.小B请你帮助他回答询问. 输入输出格式 输入格式: 第一行,三个整数N.M.K. 第二行,N个整数,表示小B的序列. 接下来的M行,每行两个整数L.R. 输出格式: M行,每行一个整数,其中第i行的整数表示第i个询问的答案. 输入输出样例 输入样例#1: 6 4 3 1 3 2 1 1 3

BZOJ 1012: [JSOI2008]最大数maxnumber(线段树)

012: [JSOI2008]最大数maxnumber Time Limit: 3 Sec  Memory Limit: 162 MB Description 现在请求你维护一个数列,要求提供以下两种操作:1. 查询操作.语法:Q L 功能:查询当前数列中末尾L个数中的最大的数,并输出这个数的值.限制:L不超过当前数列的长度.2. 插入操作.语法:A n 功能:将n加上t,其中t是最近一次查询操作的答案(如果还未执行过查询操作,则t=0),并将所得结果对一个固定的常数D取模,将所得答案插入到数列

【BZOJ】【1016】【JSOI2008】最小生成树计数

Kruskal/并查集+枚举 唉我还是too naive,orz Hzwer 一开始我是想:最小生成树删掉一条边,再加上一条边仍是最小生成树,那么这两条边权值必须相等,但我也可以去掉两条权值为1和3的,再加上权值为2和2的,不也满足题意吗?事实上,如果这样的话……最小生成树应该是1和2,而不是1和3或2和2!!! 所以呢?所以对于一个图来说,最小生成树有几条边权为多少的边,都是固定的!所以我们可以做一遍Kruskal找出这些边权,以及每种边权出现的次数.然后,对于每种边权,比方说出现了$v_i$

【BZOJ】【2844】albus就是要第一个出场

高斯消元解XOR方程组 srO  ZYF  Orz 膜拜ZYF…… http://www.cnblogs.com/zyfzyf/p/4232100.html 1 /************************************************************** 2 Problem: 2844 3 User: Tunix 4 Language: C++ 5 Result: Accepted 6 Time:252 ms 7 Memory:2052 kb 8 *******