CSP23次(202109-5)箱根山岳险天下

题目分析:

        看到要对于历史状态进行操作,那不是主席树啊!

        其实不然,问题虽然需要根据历史状态进行操作,但是操作还是对于当前状态,因此不是主席树。

        细看问题,发现每次操作 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;
}

  • 7
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
题目描述: 农夫约翰想要丈量他的 N(1≤N≤100,000)个田地的面积。他有一条长为 L(1≤L≤1,000,000)的量尺,可以用来测量在一个平面上的距离。每个田地都是一个矩形,且所有矩形的边都平行于坐标轴。每个矩形的左下角和右上角的坐标分别为 (x1,y1) 和 (x2,y2),其中 0≤x1<x2≤L,0≤y1<y2≤L。你需要编写一个程序来计算所有田地的总面积。 输入格式: 第一行包含两个整数 N 和 L。 接下来 N 行,每行包含四个整数 x1,y1,x2,y2,表示一个矩形的左下角和右上角坐标。 输出格式: 输出所有田地的总面积。 样例输入: 3 10 0 0 1 1 1 1 5 5 5 5 10 10 样例输出: 100 解题思路: 首先,根据输入的坐标信息,我们可以计算出每个矩形的面积。这个很简单,只需要将矩形的宽和高相乘即可。 然后,我们需要判断每个矩形是否与其他矩形重叠。如果重叠了,我们就需要将重叠的部分减掉。这个问题也很简单,只需要找出所有相交的矩形,计算它们重叠的面积,然后将它们的面积减掉即可。 最后,将所有矩形的面积加起来,就是所有田地的总面积了。 具体实现时,我们可以使用一个二维数组来表示每个坐标上的矩形数量。然后,我们可以对每个矩形进行遍历,找出所有与它相交的矩形,并计算它们的重叠面积。最后,将所有矩形的面积加起来即可。 参考代码:

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值