• [CF607D]Power Tree


    题目大意:
      一棵树初始只有一个编号为$1$的权值为$w_1$的根。$q(qle2 imes10^5)$次操作,每次可以给出$v,w(w<10^9)$,新建一个结点作为$v$的子结点,权值为$w$;或者给出$u$,求出$f(u)$。定义$f(u)=|S|cdotsum_{din S}d$,其中$S$为$w_u$与其所有子结点$v$的$f(v)$构成的可重集合。

    思路:
      首先将树全部建好,用线段树维护DFS序。每次新加结点相当于将这一结点的权值由$0$变为$w$,用线段树计算加上这个点以后的贡献。题目就变成了线段树上单点加、区间乘、区间求和问题。时间复杂度$O(q(log n+log w))$,其中$O(log w)$是求逆元的复杂度。

      1 #include<cstdio>
      2 #include<cctype>
      3 #include<forward_list>
      4 using int64=long long;
      5 inline int getint() {
      6     register char ch;
      7     while(!isdigit(ch=getchar()));
      8     register int x=ch^'0';
      9     while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
     10     return x; 
     11 }
     12 constexpr int N=2e5+1,Q=2e5,mod=1e9+7;
     13 int w[N],n,dfn[N],par[N],size[N],s[N];
     14 std::forward_list<int> e[N];
     15 inline void add_edge(const int &u,const int &v) {
     16     e[u].push_front(v);
     17 }
     18 struct Operation {
     19     int type,v,u;
     20 };
     21 Operation o[N];
     22 void exgcd(const int &a,const int &b,int &x,int &y) {
     23     if(!b) {
     24         x=1,y=0;
     25         return;
     26     }
     27     exgcd(b,a%b,y,x);
     28     y-=a/b*x;
     29 }
     30 int inv(const int &x) {
     31     int ret,tmp;
     32     exgcd(x,mod,ret,tmp);
     33     return (ret%mod+mod)%mod;
     34 }
     35 void dfs(const int &x) {
     36     size[x]=1;
     37     dfn[x]=++dfn[0];
     38     for(auto &y:e[x]) {
     39         dfs(y);
     40         size[x]+=size[y];
     41     }
     42 }
     43 class SegmentTree {
     44     #define _left <<1
     45     #define _right <<1|1
     46     private:
     47         int val[N<<2],tag[N<<2];
     48         void push_up(const int &p) {
     49             val[p]=(val[p _left]+val[p _right])%mod;
     50         }
     51         void push_down(const int &p) {
     52             if(tag[p]==1) return;
     53             tag[p _left]=(int64)tag[p _left]*tag[p]%mod;
     54             tag[p _right]=(int64)tag[p _right]*tag[p]%mod;
     55             val[p _left]=(int64)val[p _left]*tag[p]%mod;
     56             val[p _right]=(int64)val[p _right]*tag[p]%mod;
     57             tag[p]=1;
     58         }
     59     public:
     60         void build(const int &p,const int &b,const int &e) {
     61             tag[p]=1;
     62             if(b==e) return;
     63             const int mid=(b+e)>>1;
     64             build(p _left,b,mid);
     65             build(p _right,mid+1,e);
     66         }
     67         void add(const int &p,const int &b,const int &e,const int &x,const int &v) {
     68             (val[p]+=v)%=mod;
     69             if(b==e) return;
     70             push_down(p);
     71             const int mid=(b+e)>>1;
     72             if(x<=mid) add(p _left,b,mid,x,v);
     73             if(x>mid) add(p _right,mid+1,e,x,v);
     74         }
     75         void mul(const int &p,const int &b,const int &e,const int &l,const int &r,const int &v) {
     76             if(b==l&&e==r) {
     77                 val[p]=(int64)val[p]*v%mod;
     78                 tag[p]=(int64)tag[p]*v%mod;
     79                 return;
     80             }
     81             push_down(p);
     82             const int mid=(b+e)>>1;
     83             if(l<=mid) mul(p _left,b,mid,l,std::min(mid,r),v);
     84             if(r>mid) mul(p _right,mid+1,e,std::max(mid+1,l),r,v);
     85             push_up(p);
     86         }
     87         int query(const int &p,const int &b,const int &e,const int &l,const int &r) {
     88             if(b==l&&e==r) {
     89                 return val[p];
     90             }
     91             push_down(p);
     92             int ret=0;
     93             const int mid=(b+e)>>1;
     94             if(l<=mid) (ret+=query(p _left,b,mid,l,std::min(mid,r)))%=mod;
     95             if(r>mid) (ret+=query(p _right,mid+1,e,std::max(mid+1,l),r))%=mod;
     96             return ret;
     97         }
     98     #undef _left
     99     #undef _right
    100 };
    101 SegmentTree t;
    102 int main() {
    103     w[n=1]=getint();
    104     const int q=getint();
    105     for(register int i=0;i<q;i++) {
    106         o[i].type=getint();
    107         if(o[i].type==1) {
    108             o[i].v=par[++n]=getint();
    109             add_edge(par[n],n);
    110             w[o[i].u=n]=getint();
    111         }
    112         if(o[i].type==2) {
    113             o[i].v=getint();
    114         }
    115     }
    116     dfs(1);
    117     s[1]=1;
    118     t.build(1,1,n);
    119     t.add(1,1,n,1,w[1]);
    120     for(register int i=0;i<q;i++) {
    121         const int &y=o[i].u,&x=o[i].v;
    122         if(o[i].type==1) {
    123             t.add(1,1,n,dfn[y],(int64)t.query(1,1,n,dfn[x],dfn[x])*inv(w[x])%mod*w[y]%mod);
    124             t.mul(1,1,n,dfn[x],dfn[x]+size[x]-1,(int64)inv(s[x])*(s[x]+1)%mod);
    125             s[x]+=s[y]=1;
    126         }
    127         if(o[i].type==2) {
    128             const int ans=t.query(1,1,n,dfn[x],dfn[x]+size[x]-1);
    129             if(x==1) {
    130                 printf("%d
    ",ans);
    131                 continue;
    132             }
    133             printf("%d
    ",int((int64)ans*w[par[x]]%mod*inv(t.query(1,1,n,dfn[par[x]],dfn[par[x]]))%mod));
    134         }
    135     }
    136     return 0;
    137 }
  • 相关阅读:
    节点
    class 属性、div 属性
    认识 DOM
    配置 jQuery、初识 jQuery
    JavaScript 【在HTML中使用 JavaScript】
    我的第一个 jQuery 脚本
    JavaScript 【函数属性】
    【Class 继承】super 关键字
    Object.assign( )
    【华为云技术分享】云图说|人工智能新科技—文字识别服务
  • 原文地址:https://www.cnblogs.com/skylee03/p/9073802.html
Copyright © 2020-2023  润新知