• 【题解】CF575I Robots Protection


    CF 官网链接 CF.ML 链接

    • (N le 5000, Q le 10^5)
    • (N le 3 imes 10^5, Q le 3 imes 10^5)

    思路

    这是一道二维数点题。

    只考虑 (dir = 1),记一个三角形直角顶点 ((p, q)) ,直角边长 (r)

    考虑斜边的限制,斜边的方程是 (x + y = p + q + r)

    所以如果一个三角形对询问有贡献,记询问点 ((x, y)) ,则(x + y in [p + q, p + q + r])

    同时 ((p, q))((x, y)) 左下角,有 (p le x,q le y)

    所以这是个三维数点?这样是很浪费的,既然限制了 (x + y) 还要同时限制 (x, y) 两维,没什么用。

    发现不可能同时有 (p > x, q > y),那么两维就是独立的,可以容斥计算出来。

    分别统计 (p le x, q le y) 的数量,这样满足两个条件的被算了两次,不满足条件的算了一次,再减去满足第一个条件的点的总数,就可以了。

    对于第一个条件,写分治的话就归并维护 (ge p + q) ,再维护一个优先队列,维护 (le p + q + r) 即可,其实写树套树除了常数大码量大也没什么缺点,当然原来的数据范围写二维树状数组就好。

    然后将图旋转 (4) 次即可。

    (mathcal O(N log^2 N))

    Code

    旋转的时候 (N,Q) 写反了,调了 2h...

    下次变量名还是写准确点吧。

    #include <cstdio>
    #include <cctype>
    #include <cstring>
    #include <algorithm>
    #include <queue>
    #include <cassert>
    using namespace std;
    #define File(s) freopen(s".in", "r", stdin), freopen(s".out", "w", stdout)
    typedef long long ll;
    namespace io {
    	const int SIZE = (1 << 21) + 1;
    	char ibuf[SIZE], *iS, *iT, obuf[SIZE], *oS = obuf, *oT = oS + SIZE - 1, c, qu[55]; int f, qr;
    	#define gc() (iS == iT ? (iT = (iS = ibuf) + fread (ibuf, 1, SIZE, stdin), (iS == iT ? EOF : *iS ++)) : *iS ++)
    	char getc () {return gc();}
    	inline void flush () {fwrite (obuf, 1, oS - obuf, stdout); oS = obuf;}
    	inline void putc (char x) {*oS ++ = x; if (oS == oT) flush ();}
    	template <class I> inline void gi (I &x) {for (f = 1, c = gc(); c < '0' || c > '9'; c = gc()) if (c == '-') f = -1;for (x = 0; c <= '9' && c >= '0'; c = gc()) x = x * 10 + (c & 15); x *= f;}
    	template <class I> inline void print (I x) {if (!x) putc ('0'); if (x < 0) putc ('-'), x = -x;while (x) qu[++ qr] = x % 10 + '0',  x /= 10;while (qr) putc (qu[qr --]);}
    	struct Flusher_ {~Flusher_(){flush();}}io_flusher_;
    }
    using io :: gi; using io :: putc; using io :: print; using io :: getc;
    template<class T> void upmax(T &x, T y){x = x>y ? x : y;}
    template<class T> void upmin(T &x, T y){x = x<y ? x : y;}
    const int N = 300005;
    int bit[N];
    int n;
    struct BIT{
    	int tr[N];
    	void modify(int p, int v){
    		for(; p<=n; p += p & -p) tr[p] += v;
    	}
    	int query(int p){
    		int s = 0;
    		for(; p; p ^= (p & -p)) s += tr[p];
    		return s;
    	}
    }Tx, Ty;
    
    const int dirMap[] = {0, 0, 1, 3, 2};
    
    struct Query{
    	int d, x, y, r;
    }tq[N], q[N], tp[N];
    
    void rotateMap(int Q){
    	for(int i=1; i<=Q; i++){
    		int tx, ty;
    		tx = tq[i].y; ty = n + 1 - tq[i].x;
    		tq[i].x = tx; tq[i].y = ty;
    		if(tq[i].d != 4) tq[i].d = (tq[i].d + 1) % 4;
    	}
    }
    
    int res[N];
    
    struct Elem{
    	int x, y, v;
    	Elem(int _x, int _y, int _v) : x(_x), y(_y), v(_v) {}
    	inline bool operator<(const Elem &rhs) const {return v > rhs.v;} // min heap
    };
    void solve(int l, int r){
    	if(l >= r) return ;
    	int mid = (l + r) >> 1;
    	solve(l, mid); solve(mid + 1, r);
    	priority_queue<Elem> act;
    	int p = l, pt = 0, cnt = 0;
    	for(int i=mid+1; i<=r; i++){
    		while(p <= mid && q[p].x + q[p].y <= q[i].x + q[i].y){
    			if(q[p].d == 0){
    				Elem e(q[p].x, q[p].y, q[p].x + q[p].y + q[p].r);
    				act.push(e); ++cnt;
    				Tx.modify(e.x, 1); Ty.modify(e.y, 1);
    			}
    			tp[pt++] = q[p++];
    		}
    		if(q[i].d == 4){
    			while(!act.empty() && act.top().v < q[i].x + q[i].y){
    				Elem e = act.top();
    				--cnt;
    				Tx.modify(e.x, -1); Ty.modify(e.y, -1);
    				act.pop();
    			}
    			res[q[i].r] += Tx.query(q[i].x) + Ty.query(q[i].y) - cnt;
    		}
    		tp[pt++] = q[i];
    	}
    	while(!act.empty()){
    		Elem e = act.top(); act.pop();
    		Tx.modify(e.x, -1); Ty.modify(e.y, -1);
    	}
    	while(p <= mid) tp[pt++] = q[p++];
    	copy_n(tp, r - l + 1, q + l);
    }
    
    int main(){
    	int Q;
    	gi(n); gi(Q);
    	int ansc = 0;
    	for(int i=1; i<=Q; i++){
    		int opt; gi(opt);
    		if(opt == 2){
    			gi(tq[i].x); gi(tq[i].y);
    			tq[i].d = 4; tq[i].r = ++ansc;
    		}
    		else{
    			gi(tq[i].d); gi(tq[i].x); gi(tq[i].y); gi(tq[i].r);
    			tq[i].d = dirMap[tq[i].d];
    		}
    	}
    	for(int i=0; i<4; i++){
    		int qc = 0;
    		for(int i=1; i<=Q; i++)
    			if(tq[i].d == 0 || tq[i].d == 4) q[++qc] = tq[i];
    		solve(1, qc);
    		rotateMap(Q);
    	}
    	for(int i=1; i<=ansc; i++) print(res[i]), putc('
    ');
    	return 0;
    }
    
  • 相关阅读:
    awk语法
    Linux 统计某个字符串出现的次数
    Linux 输出文件列数,拼接文件
    Linux之date
    C变量类型和作用域
    Java垃圾回收机制
    python 字符编码问题
    Linux文件和windows文件在 换行符的区别
    不要在 foreach 循环里进行元素的 remove/add 操作。remove 元素请使用 Iterator 方式,如果并发操作,需要对 Iterator 对象加锁
    Iterator和ListIterator
  • 原文地址:https://www.cnblogs.com/RiverHamster/p/sol-cf575i.html
Copyright © 2020-2023  润新知