WA一晚上,AC树链剖分加线段树区间操作

本文分享了一段关于树状结构中跳链维护与区间更新的代码实现过程,重点介绍了如何正确维护边方向以避免运行时错误。通过具体示例展示了在解决复杂数据结构问题时的调试技巧。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

见https://www.luogu.org/record/lists?pid=P3384&uid=&flag=&page=2

wa了一晚上,原来是跳链时的维护反了边,详见代码,哈哈,终于ac了,不容易啊

#include<cstdio>
#include<cstdlib>
#include<iostream>
#define M 110000
#define LL long long
#define reg register
#define REP(i,a,b) for(int i=(int)a; i<=(int)b; ++i)
#define NODES(i,h,a,b) for(int i=a[h]; i; i=b[i])
using namespace std;
int cnt, gen;
int bgn[M], to[M<<1], nxt[M<<1];
LL w[M];
int siz[M], fa[M], top[M], son[M], dep[M];
int ru[M], chu[M];
LL sum[M<<2], addv[M<<2];
int ti, e;
LL mod;
int n, m;
LL asksum;
void edge(int x,int y) {to[e]=y; nxt[e]=bgn[x]; bgn[x]=e; ++e;}
struct Chain
{
  void line(int h, int g, int dep_)
  { 
    siz[h] = 1;
    son[h] = 0;
    fa[h] = g;
    dep[h] = dep_;
    NODES(i,h,bgn,nxt)
    {
      int y = to[i];
      if(y == g) continue;
      line(y, h, dep_+1);
      siz[h] += siz[y];
      if(siz[y] > siz[son[h]]) son[h] = y;
    }
  }

  void zip(int h, int g)
  {
    top[h] = g;
    ru[h] = ++ti;
    if(son[h]) zip(son[h], g);
    NODES(i,h,bgn,nxt)
    {
      int y = to[i];
      if(y == fa[h]) continue;
      if(y == son[h]) continue;
      zip(y, y);
    }
    chu[h] = ti;
  }

  void getchain()
  {
    line(gen, gen, 1);
    zip(gen, gen);
  }
  
  void maintain(int h, int l, int r)
  {
    if(l < r) 
    {
      sum[h] = (sum[(h<<1)] + sum[(h<<1)|1]) % mod;
    }
    if(addv[h])
    {
      sum[h] = (sum[h] + (LL)(r - l + 1) * addv[h]) % mod;
    }
    if(l == r) addv[h] = 0LL;
  }
  
  void pushdown(int h)
  {
    if(addv[h])
    {
      addv[h<<1] += addv[h];
      addv[h<<1] %= mod;
      addv[(h<<1)|1] += addv[h];
      addv[(h<<1)|1] %= mod;
      addv[h] = 0LL;
    }
  }
  
  void add(int h,int l,int r,int y1,int y2,LL v)
  {
    if(y1 <= l && r <= y2)
    {
      addv[h] += v;
      addv[h] %= mod;
    }
    else
    {
      pushdown(h);
      int m = (l + r) >> 1;
      if(y1 <= m) add((h<<1), l, m, y1, y2, v); else maintain((h<<1),l,m); 
      if(m  < y2) add((h<<1)|1,m+1,r, y1, y2, v);else maintain((h<<1)|1,m+1,r);
    }
    maintain(h, l, r);
  }
  
  void query(int h,int l,int r,int y1,int y2,LL add_)
  {
    if(y1 <= l && r <= y2)
    {
      LL p = sum[h] + ((add_) * (LL)(min(r, y2) - max(l, y1) + 1)) % mod;
      asksum += p;
      asksum %= mod;
    }
    else
    {
      int m = (l + r) >> 1;
      if(y1 <= m) query(h<<1, l, m, y1, y2, add_+addv[h]);
      if(m  < y2) query((h<<1)|1, m+1, r, y1, y2, add_+addv[h]);
    }
  }
  
  void getSegmenttree()
  {  
    for(int i=1; i<=n; ++i) 
    {
      add(1, 1, n, ru[i], ru[i], w[i]);
    }
    asksum = 0;
  }
    
  void askson(int h)
  {
    asksum = 0;
    query(1, 1, n, ru[h], chu[h], 0);
    asksum%=mod;
    printf("%lld\n",asksum);
  }
  
  void addson(int h,int v)
  {
    add(1, 1, n, ru[h], chu[h], v);
  }
  
  void askroad(int x,int y)
  {
    asksum = 0;
    while(top[x] != top[y])
    {
      if(dep[top[x]] < dep[top[y]]) swap(x, y);
      query(1, 1, n, ru[top[x]], ru[x], 0);
      asksum%=mod;
      x = fa[top[x]];
    }
    if(dep[x] > dep[y]) swap(x, y);
    query(1, 1, n, ru[x], ru[y], 0);
    asksum%=mod;
    printf("%lld\n",asksum);
  }
  
  void addroad(int x,int y,int v)
  {
    while(top[x] != top[y])
    {
      if(dep[top[x]] < dep[top[y]]) swap(x, y);
      add(1, 1, n, ru[top[x]], ru[x], v);
      asksum%=mod;
      x = fa[top[x]];
    }
    if(dep[x] > dep[y]) swap(x, y);
    add(1, 1, n, ru[x], ru[y], v);
    asksum%=mod;
  }
  
  void work(int m)
  {
    getchain();
    getSegmenttree();
    int ord, x, y;
    LL z;
    while(m--)
    {
      scanf("%d",&ord);
      //printf("%d\n",ord);
      if(ord == 1) { scanf("%d%d%lld",&x,&y,&z); addroad(x, y, z);}
      if(ord == 2) { scanf("%d%d",&x,&y); askroad(x, y);}
      if(ord == 3) { scanf("%d%lld",&x,&z); addson(x, z);}
      if(ord == 4) { scanf("%d",&x); askson(x);}
    }
  }
} tree;

int main()
{
  int x, y, z;
  //freopen("in.txt","r",stdin);
  //freopen("out.txt","w",stdout);
  scanf("%d%d%d%lld",&n,&m,&gen,&mod);
  REP(i, 1, n) scanf("%lld",&w[i]);
  REP(i, 1, n-1)
  {
    scanf("%d%d",&x,&y);
    edge(x, y);
    edge(y, x);
  }
  tree.work(m);
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值