• [luoguP3960] 列队(动态开点线段树)


    传送门

    有splay的做法,有树状数组的做法。。。

    最好理解的还是线段树的做法。

    一开始我是这样想的,如果移动某一个人,只有当前行和最后一列会受到影响,感觉就像是个线段树,树状数组什么的。

    然而接下来就想歪了,把一个人移到后面,等于把后面的整体往前移一格,gg

    正确思路是权值线段树,如果一个数被移走,相当于这个数的个数-1,然后把它变成了m+1,放到后面。

    移动第x行第y个人其实就是求第x行的第y大。

    这样,每一行和最后一列建一棵线段树,然而超空间。

    所以需要动态开点,因为总共只移动3*10^5次,也就是开nlongn的点。

    据说逆向思维可以骗50分,这都没想到。。。

    最后附上丑陋的,调了一晚上的,连我自己都看不懂的代码——

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #define N 600001
    #define LL long long
    
    using namespace std;
    
    int n, m, q, M, cnt;
    int size[N], sum[N * 10], ls[N * 10], rs[N * 10], root[N];
    LL val[N * 10];
    
    inline int read()
    {
    	int x = 0, f = 1;
    	char ch = getchar();
    	for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = -1;
    	for(; isdigit(ch); ch = getchar()) x = (x << 1) + (x << 3) + ch - '0';
    	return x * f;
    }
    
    inline LL del(int &now, int l, int r, int x, int f, int h)
    {
    	if(!now) now = ++cnt;
    	sum[now]--;
    	if(l == r)
    	{
    		if(!f) return val[now] ? val[now] : (LL)(h - 1) * m + l;
    		return val[now] ? val[now] : (LL)l * m;
    	}
    	int mid = (l + r) >> 1;
    	if(mid - l + 1 + sum[ls[now]] >= x) return del(ls[now], l, mid, x, f, h);
    	else return del(rs[now], mid + 1, r, x - (mid - l + 1 + sum[ls[now]]), f, h); 
    }
    
    inline void insert(int &now, int l, int r, int x, LL d)
    {
    	if(!now) now = ++cnt;
    	if(l == r)
    	{
    		val[now] = d;
    		return;
    	}
    	int mid = (l + r) >> 1;
    	if(x <= mid) insert(ls[now], l, mid, x, d);
    	else insert(rs[now], mid + 1, r, x, d);
    }
    
    int main()
    {
    	int i, x, y;
    	LL a, b;
    	n = read();
    	m = read();
    	q = read();
    	M = max(n, m) + q;
    	size[0] = n;
    	for(i = 1; i <= n; i++) size[i] = m - 1;
    	while(q--)
    	{
    		x = read();
    		y = read();
    		if(y != m) a = del(root[x], 1, M, y, 0, x);
    		b = del(root[0], 1, M, x, 1, x);
    		printf("%lld
    ", y == m ? a = b : a);
    		if(y != m)
    		{
    			++size[x];
    			insert(root[x], 1, M, size[x], b);
    		}
    		++size[0];
    		insert(root[0], 1, M, size[0], a);
    	}
    	return 0;
    }
    

      

    就让这个题作为我回归奥赛的开端,SDOI2018加油!

  • 相关阅读:
    《一起》个人进展——Day05
    《一起》个人进展——Day04
    《一起》个人进展——Day03
    《一起》个人进展——Day02
    《一起》个人进展——Day01
    this
    java_流
    input _文本框回车或者失去光标触发事件
    removeAll
    SysLog简介和java操作实例
  • 原文地址:https://www.cnblogs.com/zhenghaotian/p/8137922.html
Copyright © 2020-2023  润新知