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
    
    
    */
    
  • 相关阅读:
    URAL 2067 Friends and Berries (推理,数学)
    URAL 2070 Interesting Numbers (找规律)
    URAL 2073 Log Files (模拟)
    URAL 2069 Hard Rock (最短路)
    URAL 2068 Game of Nuts (博弈)
    URAL 2066 Simple Expression (水题,暴力)
    URAL 2065 Different Sums (找规律)
    UVa 1640 The Counting Problem (数学,区间计数)
    UVa 1630 Folding (区间DP)
    UVa 1629 Cake slicing (记忆化搜索)
  • 原文地址:https://www.cnblogs.com/Hs-black/p/13594182.html
Copyright © 2011-2022 走看看