luogu P3787 冰精冻西瓜
P3787 冰精冻西瓜 树状数组/线段树 标记
Time cost:75min
其实这题本来想昨天做的,但是昨天知识点全一样(还有点水)有点不太好
所以就把这个有点小难的题留到今天做左偏树去了
这个题难度在于转化
考虑边权为0的边 乘上这个毒瘤边之后v的祖节点就不能影响到v的子树
所以可以把下面的树单独拿出来做一棵根节点为v的树
在这之前(或者想到这一步的时候)就能想到子树的题可以转化为dfs序之后乘标记
有一个问题就是子树上的点是无法打标记的否则要建n棵线段树下放标记
这个时候之前拆树的思路就用上了
如果路径上没有边权0那么可以把在这个点上的标记向上推到根节点上
所以可以对于每个切完的树只建一棵线段树
这样就可以视为每个操作1都是从根节点推下来的
由于区间加是从子树根到子树尾所以不会影响其他的区间
然后吃细节的地方就是double判0……以及输入的问题
注意第一遍dfs完了要接着处理被断开的子树
Code:
1 #include<cstdio> 2 #include<algorithm> 3 #include<cstring> 4 #include<cmath> 5 #define rep(i,a,n) for(int i = a;i <= n;i++) 6 #define per(i,n,a) for(int i = n;i >= a;i--) 7 #define ms(a,b) memset(a,b,sizeof a) 8 using namespace std; 9 typedef long long ll; 10 ll read() { 11 ll as = 0,fu = 1; 12 char c = getchar(); 13 while(c < '0' || c > '9') { 14 if(c == '-') fu = -1; 15 c = getchar(); 16 } 17 while(c >= '0' && c <= '9') { 18 as = as * 10 + c - '0'; 19 c = getchar(); 20 } 21 return as * fu; 22 } 23 typedef double D; 24 const int N = 300005; 25 #define eps 1e-8 26 inline D zero(D x) { 27 return fabs(x) <= eps; 28 } 29 //head 30 int n,m; 31 int head[N],nxt[N],mo[N],cnt; 32 D cst[N]; 33 inline void addedge(int x,int y,D z) { 34 mo[++cnt] = y; 35 cst[cnt] = z; 36 nxt[cnt] = head[x]; 37 head[x] = cnt; 38 return; 39 } 40 41 int dfn[N],str[N],stp[N]; 42 int rt[N],idx,cur,top; 43 D val[N]; 44 bool vis[N]; 45 void dfs(int x,int f,D dis) { 46 vis[x] = 1; 47 val[x] = dis; 48 dfn[++idx] = x; 49 str[x] = idx; 50 for(int i = head[x];i;i = nxt[i]) { 51 int sn = mo[i]; 52 if(sn == f || vis[sn]) continue; 53 if(zero(cst[i])) { 54 //CUT LINE 55 rt[++cur] = sn; 56 continue; 57 } 58 dfs(sn,x,dis * cst[i]); 59 } 60 stp[x] = idx; 61 return; 62 } 63 64 D p[N<<2],add[N<<2]; 65 #define ls t<<1 66 #define rs t<<1|1 67 void pdown(int t) { 68 if(zero(add[t])) return; 69 p[ls] += add[t]; 70 p[rs] += add[t]; 71 add[ls] += add[t]; 72 add[rs] += add[t]; 73 add[t] = 0; 74 return; 75 } 76 77 void update(int L,int R,D c,int l,int r,int t) { 78 if(L <= l && r <= R) { 79 p[t] += c; 80 add[t] += c; 81 return; 82 } 83 pdown(t); 84 int m = l+r >> 1; 85 if(L <= m) update(L,R,c,l,m,ls); 86 if(R > m) update(L,R,c,m+1,r,rs); 87 return; 88 } 89 90 D query(int L,int l,int r,int t) { 91 if(l == r) return p[t] * val[dfn[L]]; 92 pdown(t); 93 int m = l+r >> 1; 94 D ans = 0; 95 if(L <= m) ans += query(L,l,m,ls); 96 else ans += query(L,m+1,r,rs); 97 return ans; 98 } 99 100 int main() { 101 n = read(); 102 rep(i,1,n-1) { 103 int x,y; 104 D l; 105 scanf("%d%d%lf",&x,&y,&l); 106 if(zero(l)) top++; 107 addedge(x,y,l),addedge(y,x,l); 108 } 109 dfs(1,1,1.0); 110 rep(i,1,cur) dfs(rt[i],rt[i],1.0); 111 int T = read(); 112 while(T--) { 113 int op = read(),x; 114 if(op == 1) { 115 D y; 116 scanf("%d%lf",&x,&y); 117 update(str[x],stp[x],y / val[x],1,idx,1); 118 } else { 119 x = read(); 120 printf("%.8lf\n",query(str[x],1,idx,1)); 121 } 122 } 123 return 0; 124 }
> 别忘了 总有人在等着你