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
",query(str[x],1,idx,1));
121     }
122     }
123     return 0;
124 }
> 别忘了 总有人在等着你
原文地址:https://www.cnblogs.com/yuyanjiaB/p/9687666.html