zoukankan      html  css  js  c++  java
  • [CSP-SJX2019]散步(模拟)

    [CSP-SJX2019]散步(模拟)

    题目大意

    公园内有 (n) 个人正在散步,随着天色渐晚,所有人准备回家离开公园。公园的结构是一个首尾相连的环形图,它共有 (m) 个出口,为了方便叙述,我们将人从 (1sim n) 编号,将出口按逆时针顺序从 (1sim m) 编号。

    公园总长 (L) 米,我们令 (1) 号出口所在的位置为 (0) 米,则 编号为 (i(2le ile m)) 的出口在 (1) 号出口逆时针方向 (a_i) 米的位置上,其中 (a_i) 严格递增 ,即 (i(1le i le m)) 号出口与 (i+1) 号出口相邻,由于公园是环形图,故 (m) 号出口与 (1) 号出口也相邻。每个出口还有一个通行限制 (l_i),表示最多有 (l_i) 个人能从 (i) 号出口离开。

    所有人回家时将按自己的朝向,可能是顺时针方向,也可能是逆时针方向不断前行,当他们走到一个还能离开的出口时,将从该出口离开公园。特别地,当两个人同时走到一个只能允许 (1) 个人离开的出口时,编号小的那个人能从该出口离开,编号较大的人将继续前进。

    现在给定 (n) 个人所在的起始位置与他们的前进方向,请你求出每个人从哪个出口离开,若编号为 (i) 的 人从 (k_i) 号出口离开,你只需要给出 (i imes k_i) 的异或和,即:

    [(1 imes k_1) operatorname{xor} (2 imes k_2) operatorname{xor}cdots operatorname{xor} (n imes k_n) ]

    其中 (operatorname{xor}) 是位异或运算。特别地若一个人最后无法离开,则他的 (k_i = 0)

    数据范围

    对于 (12\%) 的数据: (n, m, L le 10)
    对于 (32\%) 的数据: (n, m le 100 , L le 1000)
    对于 (52\%) 的数据: (n, m le 1000)
    另有 (20\%) 的数据: (n, m le 10000) ,所有 (s_i = 0)
    对于 (100\%) 的数据: (1 le n,m le 2 imes 10^5 , 2 le L le 10^9 , 1le a_i le L 1le l_i le n, s_iin{0,1} , 0le b_i le L)

    解题思路

    思路挺显然,代码却不是这样。

    暴力就是每个点找到最近的那个出口,然后用大根堆维护一下即可,时间复杂度 (Theta(n^2log n)),当然我们发现这个过程中的瓶颈在于更新 queue,如果每次暴力扫一遍就可以做到 (Theta(n^2)),这提醒我们每次找到最大的而不是更新以后立刻放到队列里,又发现更新的人将要去同一个出口,所以我们可以用线段树维护,这样要修改的人就在一个连续段上,从一个出口到下一个出口,这些人的目标距离都要增加这些距离,那么区间加即可,然后查询时询问最值即可。

    这么说起来好像很简单,但是实现起来并不是这样的,你需要写两颗线段树来维护顺时针和逆时针,需要处理到同一个出口的连续段的左右端点,需要处理换上跨过 1,m 的情况。还要用链表删除出口,这样的话就可以 A 掉了。自己做出这题感觉还是蛮有成就的呐。目前是洛谷最优解。

    /*
         />  フ
         |  _  _|
         /`ミ _x 彡
         /      |
        /   ヽ   ?
     / ̄|   | | |
     | ( ̄ヽ__ヽ_)_)
     \二つ
     */
    
    #include <queue>
    #include <vector>
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define MP make_pair
    #define ll long long
    #define fi first
    #define se second
    using namespace std;
    
    template <typename T>
    void read(T &x) {
        x = 0; bool f = 0;
        char c = getchar();
        for (;!isdigit(c);c=getchar()) if (c=='-') f=1;
        for (;isdigit(c);c=getchar()) x=x*10+(c^48);
        if (f) x=-x;
    }
    
    template<typename F>
    inline void write(F x, char ed = '
    ') {
    	static short st[30];short tp=0;
    	if(x<0) putchar('-'),x=-x;
    	do st[++tp]=x%10,x/=10; while(x);
    	while(tp) putchar('0'|st[tp--]);
    	putchar(ed);
    }
    
    template <typename T>
    inline void Mx(T &x, T y) { x < y && (x = y, 0); }
    
    template <typename T>
    inline void Mn(T &x, T y) { x > y && (x = y, 0); }
    
    const int N = 200050;
    const int inf = 1e9;
    pair<int, int> Inf(inf, inf);
    struct chain {
    	int pre, nxt;
    	int dp, dn;
    }ch[N];
    
    int jue(int x) { return x < 0 ? -x : x; }
    int pos[N], lim[N], m, L, n;
    struct SegTree {
    	#define ls p << 1
    	#define rs ls | 1
    	#define Pa pair<int, int> 
    	Pa mn[N<<2];
    	int add[N<<2], L[N], R[N], f[N], rp[N], rrp[N], n;
    	int find(int x) { return f[x] == x ? x : f[x] = find(f[x]); }
    	
    	struct node {
    		int t, num, to;
    		bool operator < (const node &i) const {
    			return to < i.to;
    		}
    	}val[N];
    	
    	void build(int p, int l, int r) {
    		if (l == r) return rp[val[l].num] = l, mn[p] = MP(val[l].t, val[l].num), void();
    		int mid = (l + r) >> 1;
    		build(ls, l, mid), build(rs, mid + 1, r);
    		mn[p] = min(mn[ls], mn[rs]);
    	}
    	void spread(int p) {
    		add[ls] += add[p], add[rs] += add[p];
    		mn[ls].fi += add[p], mn[rs].fi += add[p];
    		add[p] = 0;
    	}
    	void change(int p, int l, int r, int L, int R, int d) {
    		if (L <= l && r <= R) return mn[p].fi += d, add[p] += d, void();
    		int mid = (l + r) >> 1; if (add[p]) spread(p);
    		if (L <= mid) change(ls, l, mid, L, R, d);
    		if (R > mid) change(rs, mid + 1, r, L, R, d);
    		mn[p] = min(mn[ls], mn[rs]);
    	}
    	void Change(int p, int l, int r, int x) {
    		if (l == r) return mn[p] = Inf, void();
    		int mid = (l + r) >> 1; if (add[p]) spread(p);
    		if (x <= mid) Change(ls, l, mid, x);
    		else Change(rs, mid + 1, r, x);
    		mn[p] = min(mn[ls], mn[rs]);
    	}
    	Pa query(void) { return n ? mn[1] : Inf; }
    	void init(int nu, int t) { val[++n] = node{0, nu, t}; }
    	void prework(int fl = 0) {
    		sort(val + 1, val + n + 1); int tp = 1; 
    		for (int i = 1;i <= n; i++) {
    			while (pos[tp] < val[i].to) tp++;
    			int t = val[i].to; rpos[val[i].num] = i;
    			if (pos[tp] == val[i].to) val[i].to = tp;
    			else val[i].to = tp - fl;
    			val[i].t = jue(t - pos[val[i].to]);
    			if (val[i].to == m + 1) val[i].to = 1;
    			if (val[i].to == val[i-1].to) R[find(i-1)] = i, f[i] = i - 1;
    			else L[i] = R[i] = f[i] = i, rrp[val[i].to] = i;
    		}
    		if (n) build(1, 1, n);
    	}
    	int rpos[N];
    	int bl(int x) { return val[find(x)].to; }
    	void delit(int t, int nt, int dis, int ty) {
    		if (!rrp[t] || !n) return ;
    		int nw = rrp[t]; rrp[t] = 0;
    		if (L[nw] > R[nw]) {
    			change(1, 1, n, 1, R[nw], dis);
    			change(1, 1, n, L[nw], n, dis);
    		}
    		else change(1, 1, n, L[nw], R[nw], dis);
    		if (rrp[nt]) {
    			if (ty) L[nw] = L[rrp[nt]], f[rrp[nt]] = nw;
    			else R[nw] = R[rrp[nt]], f[rrp[nt]] = nw;
    		}
    		rrp[nt] = nw, val[nw].to = nt;
    	}
    	inline int to(int x) { return val[find(rpos[x])].to; }
    }A, B;
    
    ll ans;
    void delit(int t) {
    	if (ch[t].nxt == t) { write(ans); exit(0); }
    	A.delit(t, ch[t].nxt, ch[t].dn, 0), B.delit(t, ch[t].pre, ch[t].dp, 1);
    	int nt = ch[t].nxt, pr = ch[t].pre, dis = ch[t].dp + ch[t].dn;
    	ch[nt].pre = pr, ch[pr].nxt = nt, ch[nt].dp = ch[pr].dn = dis;
    }
    
    int main() {
    //	freopen ("hs.in","r",stdin);
    //	freopen ("hs.out","w",stdout);
    	read(n), read(m), read(L);
    	for (int i = 2;i <= m; i++) read(pos[i]);
    	for (int i = 1;i <= m; i++) read(lim[i]);
    	pos[m + 1] = L, pos[0] = L - pos[m];
    	for (int i = 1;i <= m; i++) {
    		ch[i].pre = i - 1;
    		ch[i].nxt = i + 1;
    		ch[i].dp = jue(pos[i] - pos[ch[i].pre]);
    		ch[i].dn = jue(pos[i] - pos[ch[i].nxt]);
    		if (!ch[i].pre) ch[i].pre = m;
    		if (ch[i].nxt > m) ch[i].nxt = 1;
    	}
    	pos[m + 1] = L; 
    	for (int i = 1, s, b;i <= n; i++) 
    		read(b), read(s), b ? B.init(i, s) : A.init(i, s);
    	A.prework(), B.prework(1);
    	for (int i = 1;i <= n; i++) {
    		Pa a = A.query(), b = B.query();
    		if (a < b) {
    			int t = A.to(a.se); ans ^= (ll)a.se * t; lim[t]--;
    //			write(a.se, ' '), write(t);
    			A.Change(1, 1, A.n, A.rp[a.se]);
    			if (!lim[t]) delit(t);
    		}
    		else {
    			int t = B.to(b.se); ans ^= (ll)b.se * t; lim[t]--;
    //			write(b.se, ' '), write(t);
    			B.Change(1, 1, B.n, B.rp[b.se]);
    			if (!lim[t]) delit(t);
    		}
    	}
    	write(ans);
    	return 0;
    }
    
    /*
    
    3 2 5
    2
    2 1
    0 1
    1 3
    0 4
    
    10 3 20
    15 19
    5 3 2
    0 2
    1 5
    0 4
    0 3
    0 16
    1 18
    1 12
    0 11
    0 9
    0 1
    
    10 5 50
    5 9 19 40
    1 4 2 1 1
    0 16
    1 45
    0 12
    0 8
    1 16
    0 7
    0 43
    1 1
    0 14
    0 33
    
    
    */
    
  • 相关阅读:
    Adventure C CF-665E(字典树、二进制)
    实验7投资问题
    Beautiful Array CF-1155D(DP)
    Salary Changing CF-1251D(二分)
    Beautiful Sets of Points CF-268C(乱搞)
    Vasya And Array CF1187C(构造)
    Tree Painting CF-1187E(换根DP)
    Vus the Cossack and Numbers CF-1186D(思维)
    Tree POJ-1741(点分治+树形DP)
    Magical Girl Haze 计蒜客-A1958(分层最短路)
  • 原文地址:https://www.cnblogs.com/Hs-black/p/13594182.html
Copyright © 2011-2022 走看看