题目分析:
看到要对于历史状态进行操作,那不是主席树啊!
其实不然,问题虽然需要根据历史状态进行操作,但是操作还是对于当前状态,因此不是主席树。
细看问题,发现每次操作 s 对于 s 后出现的点没有影响,即如果当前操作的 s = 10, 那么所有在 s = 10 后才出现的点是没有影响的。
此时如果只对于添加删除操作进行处理,可以发现将相同部分合并后,就是一棵树。
那么问题就转化为树上问题了
50分
问题转化成树上路径修改、查询问题,那么可以使用树链剖分+线段树
但是问题是,树链剖分需要知道树的形态,本题强制在线算法,因此只能拿到50分(离线+官方送)
100分
动态+树链剖分 = LCT,所以Link Cut Tree确实可以拿到满分。
用Eamcs写的,格式好像出了写问题
代码(50分)
#include <bits/stdc++.h>
#define ll long long
#define ls (x<<1)
#define rs (x<<1|1)
using namespace std;
struct req
{
int t, s, l, r, w;
req(int T, int S, int L, int R, int W)
: t(T), s(S), l(L), r(R), w(W) {}
} ;
const int N = 3e5+7;
int n, T, rt, tot, now;
int fa[N], siz[N], son[N];
int top[N], dep[N], lab[N], bel[N];
ll p, A, tr[N*4], lazy[N*4];
vector <int> edge[N];
vector <pair<int, int> > E[N];
vector <req> R;
void dfs1(int x) {
int mx = 0;
siz[x] = 1;
for(int y : edge[x]) {
if(y == fa[x]) continue;
dfs1(y);
if(siz[y] > siz[mx]) mx = y;
siz[x] += siz[y];
}
son[x] = mx;
}
void dfs2(int x, int ftop) {
lab[x] = ++tot;
bel[tot] = x;
top[x] = ftop;
if(son[x]) {
dfs2(son[x], ftop);
}
for(int y : edge[x]) {
if(y == fa[x] || y == son[x]) continue;
dfs2(y, y);
}
}
void push(int x) {
if(lazy[x] != 1) {
ll num = lazy[x];
lazy[x] = 1;
tr[ls] = (tr[ls]*num)%p;
tr[rs] = (tr[rs]*num)%p;
lazy[ls] = (lazy[ls]*num)%p;
lazy[rs] = (lazy[rs]*num)%p;
}
}
void ins(int x, int l, int r, int v, ll y) {
if(l == r) {
tr[x] = y;
lazy[x] = 1;
return ;
}
int mid = (l+r)>>1; push(x);
if(v <= mid) ins(ls, l, mid, v, y);
if(v > mid) ins(rs, mid+1, r, v, y);
tr[x] = (tr[ls]+tr[rs])%p;
}
void chg(int x, int l, int r, int sl, int sr, ll y) {
if(sl <= l && r <= sr) {
tr[x] = (tr[x]*y)%p;
lazy[x] = (lazy[x]*y)%p;
return ;
}
int mid = (l+r)>>1; push(x);
if(sl <= mid) chg(ls, l, mid, sl, sr, y);
if(sr > mid) chg(rs, mid+1, r, sl, sr, y);
tr[x] = (tr[ls]+tr[rs])%p;
}
ll num = 0;
void qury(int x, int l, int r, int sl, int sr) {
if(sl <= l && r <= sr) {
num = (num+tr[x])%p;
return ;
}
int mid = (l+r)>>1; push(x);
if(sl <= mid) qury(ls, l, mid, sl, sr);
if(sr > mid) qury(rs, mid+1, r, sl, sr);
}
ll get_lca(int x, int y, ll w) {
num = 0;
while(top[x]^top[y]) {
if(dep[x] > dep[y]) swap(x, y);
if(w) chg(1, 1, tot, lab[top[y]], lab[y], w);
else qury(1, 1, tot, lab[top[y]], lab[y]);
y = fa[top[y]];
}
if(dep[x] > dep[y]) swap(x, y);
if(w) chg(1, 1, tot, lab[x], lab[y], w);
else qury(1, 1, tot, lab[x], lab[y]);
return num;
}
int find(int x, int y) {
int l = 0, r = E[x].size()-1, ans = 0;
while(l <= r) {
int mid = (l+r)>>1;
if(E[x][mid].first <= y) {
ans = E[x][mid].second;
l = mid+1;
}
else r = mid-1;
}
return ans;
}
int main()
{
freopen("1.in", "r", stdin);
freopen("1.out", "w", stdout);
scanf("%d%lld%d", &n, &p, &T);
now = rt = n+1; tot = 0;
for (int i=1; i<=n*4; i++) {
lazy[i] = 1;
tr[i] = 0;
}
for(int i=1, t, s, l, r, x; i<=n; i++) {
scanf("%d", &t);
s = l = r = x = 0;
if(t == 1) {
scanf("%d", &x);
if(x == 0) {
now = fa[now];
}
else {
s = ++tot;
fa[tot] = now;
dep[tot] = dep[now]+1;
edge[now].push_back(tot);
E[dep[tot]].push_back({i, tot});
now = tot;
}
}
if(t == 2) {
scanf("%d%d%d%d", &s, &l, &r, &x);
}
if(t == 3) {
scanf("%d%d%d", &s, &l, &r);
}
R.push_back(req(t, s, l, r, x));
}
A = 0;
tot = 0;
dfs1(rt);
dfs2(rt, rt);
for (req re : R) {
if(re.t == 1) {
if(re.w) {
ins(1, 1, tot, lab[re.s], re.w^A);
}
}
else {
int x = find(re.l, re.s);
int y = find(re.r, re.s);
if(re.t == 2) {
get_lca(x, y, re.w^A);
}
else {
get_lca(x, y, 0);
printf("%lld\n", num);
if(T) A = num;
}
}
}
return 0;
}
代码(100分):
#include <bits/stdc++.h>
#define ls son[x][0]
#define rs son[x][1]
#define ll long long
using namespace std;
const int N = 3e5+7;
int n, T, now, rt, tot;
ll p, A;
vector <pair<int, int> > E[N];
int fa[N], son[N][2], dep[N], fs[N];
ll lazy[N], tr[N], stk[N], vi[N];
bool rev[N];
void clt(int x) {
tr[x] = (tr[ls]+tr[rs]+vi[x])%p;
}
void swap_son(int x) {
swap(son[x][0], son[x][1]);
rev[x] ^= 1;
}
void push(int x) {
if(rev[x]) {
if(son[x][0]) swap_son(son[x][0]);
if(son[x][1]) swap_son(son[x][1]);
rev[x] = false;
}
if(lazy[x] != 1) {
ll num = lazy[x];
lazy[x] = 1;
if(ls) {
tr[ls] = (tr[ls]*num)%p;
lazy[ls] = (lazy[ls]*num)%p;
vi[ls] = (vi[ls]*num)%p;
}
if(rs) {
tr[rs] = (tr[rs]*num)%p;
lazy[rs] = (lazy[rs]*num)%p;
vi[rs] = (vi[rs]*num)%p;
}
}
}
bool nroot(int x) {
return son[fa[x]][0] == x || son[fa[x]][1] == x;
}
int gson(int x) {
return son[fa[x]][1] == x;
}
void rotate(int x) {
int y = fa[x], z = fa[y];
int wi = gson(x);
if(nroot(y)) son[z][gson(y)] = x;
fa[x] = z;
son[y][wi] = son[x][wi^1];
if(son[y][wi]) fa[son[y][wi]] = y;
son[x][wi^1] = y;
fa[y] = x;
clt(y);
}
void splay(int x) {
int y = x, top = 0;
stk[++top] = y;
while(nroot(y)) stk[++top] = y = fa[y];
while(top) push(stk[top--]);
while(nroot(x)) {
int y = fa[x], z = fa[y];
if(nroot(y) && son[z][gson(x)] == y)
rotate(y);
rotate(x);
}
clt(x);
}
void access(int x) {
for(int y = 0; x; x = fa[y = x]) {
splay(x);
son[x][1] = y;
clt(x);
}
}
void makeroot(int x) {
access(x);
splay(x);
swap_son(x);
}
int find(int x, int y) {
int l = 0, r = E[x].size()-1, ans = 0;
while(l <= r) {
int mid = (l+r)>>1;
if(E[x][mid].first <= y) {
ans = E[x][mid].second;
l = mid+1;
}
else r = mid-1;
}
return ans;
}
int main() {
freopen("1.in", "r", stdin);
freopen("1.out", "w", stdout);
scanf("%d%lld%d", &n, &p, &T);
for(int i=1; i<=n; i++) {
tr[i] = 0;
lazy[i] = 1;
}
for(int i=1, t, s, l, r, x; i<=n; i++) {
scanf("%d", &t);
s = l = r = x = 0;
if(t == 1) {
scanf("%d", &x);
x ^= A;
if(x == 0) {
now = fs[now];
}
else {
++tot;
fa[tot] = fs[tot] = now;
dep[tot] = dep[now]+1;
vi[tot] = tr[tot] = x;
now = tot;
E[dep[now]].push_back({i, now});
}
}
else {
scanf("%d%d%d", &s, &l, &r);
if(t == 2) scanf("%d", &x);
x ^= A;
l = find(l, s);
r = find(r, s);
if(t == 2) {
makeroot(l);
access(r);
splay(r);
tr[r] = (tr[r]*x)%p;
vi[r] = (vi[r]*x)%p;
lazy[r] = (lazy[r]*x)%p;
}
if(t == 3) {
makeroot(l);
access(r);
splay(r);
printf("%lld\n", tr[r]);
if(T) A = tr[r];
}
}
}
return 0;
}