D 树上求和

树上求和

https://ac.nowcoder.com/acm/contest/6290/D

其实这是我打的第二道题……一眼可以用树剖做,于是就是树链剖分的板子题。
但其实似乎只求子树用dfs序就可以……?是我蠢了。
线段树维护平方和也是老套路了:

#include <cstdio>
#include <ctype.h>
#define DEBUG
#define int long long
const int bufSize = 1e6;
inline char nc()
{
    #ifdef DEBUG
    return getchar();
    #endif
    static char buf[bufSize],*p1 = buf,*p2 = buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,bufSize,stdin),p1==p2)?EOF:*p1++;
}
template<typename T>
inline T read(T &r)
{
    static char c;
    r=0;
    for(c = nc();!isdigit(c);) c = nc();
    for(;isdigit(c);c=nc()) r = r * 10 + c - 48;
    return r;
}
const int maxn = 1e5 + 100,maxm = 2e5 + 100;
int n,m;
struct node
{
    int to,next;
}E[maxm];
int head[maxn];
inline void add(const int &x,const int &y)
{
    static int tot = 0;
    E[++tot].next = head[x],E[tot].to = y,head[x] = tot;
}
int w[maxn];
int size[maxn],fa[maxn],son[maxn],dfn[maxn],id[maxn],cnt;
long long sum[maxn<<2],tsum[maxn<<2],tag[maxn<<2];
const int mod = 23333;
#define ls p<<1
#define rs p<<1|1
inline void pushup(const int &p){sum[p] = sum[ls] + sum[rs];tsum[p] = tsum[ls] + tsum[rs];sum[p] %= mod,tsum[p] %= mod;}
inline void pushdown(const int &l,const int &r,const int &p)
{
    if(!tag[p]) return;
    int mid = l + r >> 1;
    tsum[ls] += (mid - l + 1) * tag[p] * tag[p] + 2 * sum[ls] * tag[p];
    tsum[rs] += (r - mid) * tag[p] * tag[p] + 2 * sum[rs] * tag[p];
    sum[ls] += (mid - l + 1) * tag[p];
    sum[rs] += (r - mid) * tag[p];
    tag[ls] += tag[p],tag[rs] += tag[p];
    tsum[ls] %= mod,tsum[rs] %= mod,sum[ls] %= mod,sum[rs] %= mod,tag[ls] %= mod,tag[rs] %= mod;
    tag[p] = 0;
}
void build(int l,int r,int p)
{
    if(l == r) return (void)(sum[p] = w[id[l]] % mod,tsum[p] = (w[id[l]] * w[id[l]]) % mod);
    int mid = l + r >> 1;
    build(l, mid, ls), build(mid + 1, r, rs);
    pushup(p);
}
void modify(int l,int r,int p,int ll,int rr,long long k)
{
    if(l >= ll && r <= rr)
    {
        tsum[p] += (r - l + 1) * k * k + 2 * sum[p] * k;
        sum[p] += (r - l + 1) * k;
        tag[p] += k;
        tsum[p] %= mod,sum[p] %= mod,tag[p] %= mod;
        return;
    }
    int mid = l + r >> 1;
    pushdown(l,r,p);
    if(ll <= mid) modify(l,mid,ls,ll,rr,k);
    if(rr > mid) modify(mid + 1,r,rs,ll,rr,k);
    pushup(p);
}
long long ask(int l,int r,int p,int ll,int rr)
{
    if(l >= ll && r <= rr) return tsum[p];
    int mid = l + r >> 1,ans = 0;
    pushdown(l,r,p);
    if(ll <= mid) ans = ask(l,mid,ls,ll,rr) % mod;
    if(rr > mid) ans = (ans + ask(mid + 1,r,rs,ll,rr)) % mod;
    return ans;
}
void dfs1(int u)
{
    size[u] = 1;
    for(int p = head[u];p;p=E[p].next)
    {
        int v = E[p].to;
        if(v == fa[u]) continue;
        fa[v] = u,dfs1(v),size[u] += size[v];
        if(size[son[u]] < size[v]) son[u] = v;
    }
}
void dfs2(int u)
{
    dfn[u] = ++cnt;
    id[cnt] = u;
    if(!son[u]) return;
    dfs2(son[u]);
    for(int p = head[u];p;p=E[p].next)
    {
        int v = E[p].to;
        if(v == son[u] || v == fa[u]) continue;
        dfs2(v);
    }
}
signed main()
{
    read(n),read(m);
    for(int i = 1;i<=n;++i) read(w[i]);
    for(int i = 1;i<n;++i)
    {
        int a,b;
        read(a),read(b);
        add(a,b),add(b,a);
    }
    dfs1(1),dfs2(1);
    build(1,n,1);
    while(m--)
    {
        int opt,x,y;
        read(opt),read(x);
        if(opt == 1) read(y),modify(1,n,1,dfn[x],dfn[x] + size[x] - 1,y);
        else printf("%lld\n",ask(1,n,1,dfn[x],dfn[x] + size[x] - 1) % mod);
    }
    return 0;
}
全部评论
大佬们是怎么把这么多代码这么快的写下来的呀,是用收集的模板复制来的吗,可是正式的比赛只能手敲吗?有什么快速写模板的方法吗?
点赞 回复 分享
发布于 2020-07-15 12:02

相关推荐

谁知道呢_:bro不如吃顿疯狂星期四
点赞 评论 收藏
分享
评论
3
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务