见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);
}