zoukankan      html  css  js  c++  java
  • 【27.77%】【BZOJ 4066】简单题

    Time Limit: 50 Sec  Memory Limit: 20 MB
    Submit: 1919  Solved: 533
    [Submit][Status][Discuss]

    Description

    你有一个N*N的棋盘,每个格子内有一个整数,初始时的时候全部为0,现在需要维护两种操作:

    命令

    参数限制

    内容

    1 x y A

    1<=x,y<=N,A是正整数

    将格子x,y里的数字加上A

    2 x1 y1 x2 y2

    1<=x1<= x2<=N

    1<=y1<= y2<=N

    输出x1 y1 x2 y2这个矩形内的数字和

    3

    终止程序

    Input

    输入文件第一行一个正整数N。
    接下来每行一个操作。每条命令除第一个数字之外,
    均要异或上一次输出的答案last_ans,初始时last_ans=0。

    Output

    对于每个2操作,输出一个对应的答案。

    Sample Input

    4
    1 2 3 3
    2 1 1 3 3
    1 1 1 1
    2 1 1 0 7
    3

    Sample Output

    3
    5

    HINT

    数据规模和约定

    1<=N<=500000,操作数不超过200000个,内存限制20M,保证答案在int范围内并且解码之后数据仍合法。

    样例解释见OJ2683


    新加数据一组,但未重测----2015.05.24


    Source


    【题解】

    在做kd-tree的时候会记录这个子树的最大矩形范围。如果整个最大矩形范围都在所求的矩形范围内。就直接返回这个最大矩形所在的子树的和。

    如果不满足的话就看看当前节点是否在所求矩形内。

    如果在就先累加这个节点的。

    再递归求解左子树和右子树;

    然后加的那组数据会卡时.

    要不定时重建整棵树。(10000为周期)

    【代码】

    #include <cstdio>
    #include <algorithm>
    
    const int MAXN = 209000;
    
    using namespace std;
    
    struct point
    {
    	int d[2], ma_x[2], mi_n[2], l, r, sum, v;
    };
    
    int n, la = 0, v, root = 0, totn, a1, b1, a2, b2, now;
    point t[MAXN], op;
    
    void up_data(int rt)
    {
    	int l = t[rt].l, r = t[rt].r;
    	for (int i = 0; i <= 1; i++)
    	{
    		if (l)
    		{
    			t[rt].ma_x[i] = max(t[l].ma_x[i], t[rt].ma_x[i]);
    			t[rt].mi_n[i] = min(t[l].mi_n[i], t[rt].mi_n[i]);
    		}
    		if (r)
    		{
    			t[rt].ma_x[i] = max(t[r].ma_x[i], t[rt].ma_x[i]);
    			t[rt].mi_n[i] = min(t[r].mi_n[i], t[rt].mi_n[i]);
    		}
    	}
    	t[rt].sum = t[l].sum + t[r].sum + t[rt].v;//重建后要更新sum值。
    }
    
    void insert(int &rt, int fx)
    {
    	if (rt == 0) //创节点。更新信息
    	{
    		rt = ++totn;
    		t[rt] = op;
    		t[rt].l = t[rt].r = 0;
    		for (int i = 0; i <= 1; i++)
    			t[rt].ma_x[i] = t[rt].mi_n[i] = t[rt].d[i];
    		t[rt].sum = v;
    		t[rt].v = v;
    		return;
    	}
    	else
    	{
    		if (op.d[fx] <= t[rt].d[fx])
    			insert(t[rt].l, 1 - fx);
    		else
    			insert(t[rt].r, 1 - fx);
    	}
    	up_data(rt);
    }
    
    int query(int rt, int fx)
    {
    	if (!rt) return 0;
    	if (op.mi_n[0] <= t[rt].mi_n[0] && t[rt].ma_x[0] <= op.ma_x[0] &&
    		op.mi_n[1] <= t[rt].mi_n[1] && t[rt].ma_x[1] <= op.ma_x[1])
    		return t[rt].sum; //整个子树都在范围内
    	int temp = 0, l = t[rt].l, r = t[rt].r;
    	if (op.mi_n[0] <= t[rt].d[0] && t[rt].d[0] <= op.ma_x[0] &&
    		op.mi_n[1] <= t[rt].d[1] && t[rt].d[1] <= op.ma_x[1]) //这个点在范围内
    		temp += t[rt].sum - t[l].sum - t[r].sum; //减去两个子树的就是当前这个点的
    	//或直接加t[rt].v
    	if (op.mi_n[fx] <= t[rt].d[fx]) 
    		temp += query(l, 1 - fx);
    	if (t[rt].d[fx] <= op.ma_x[fx])
    		temp += query(r, 1 - fx);
    	return temp;
    }
    
    bool cmp(point a, point b)
    {
    	if (a.d[now] < b.d[now])
    		return true;
    	return false;
    }
    
    int build(int begin, int end, int fx)
    {
    	int m = (begin + end) >> 1;
    	now = fx;
    	nth_element(t + begin, t + m, t + end + 1, cmp);
    	for (int i = 0; i <= 1; i++)
    		t[m].ma_x[i] = t[m].mi_n[i] = t[m].d[i];
    	t[m].sum = t[m].v;
    	if (begin < m)
    		t[m].l = build(begin, m - 1, 1 - fx);
    	else
    		t[m].l = 0;
    	if (m < end)
    		t[m].r = build(m + 1, end, 1 - fx);
    	else
    		t[m].r = 0;
    	up_data(m);
    	return m;
    }
    
    void input_data()
    {
    	scanf("%d", &n);
    	while (true)
    	{
    		int cz;
    		scanf("%d", &cz);
    		if (cz == 1)
    		{
    			if ((totn != 0) && (totn % 10000) == 0) //重建树
    				root = build(1, totn, 0);
    			scanf("%d%d%d", &op.d[0], &op.d[1], &v);
    			op.d[0] ^= la; op.d[1] ^= la; v ^= la;
    			insert(root, 0);
    		}
    		else
    			if (cz == 2)
    			{
    				scanf("%d%d%d%d", &op.mi_n[0], &op.mi_n[1], &op.ma_x[0], &op.ma_x[1]);
    				op.mi_n[0] ^= la; op.mi_n[1] ^= la;
    				op.ma_x[0] ^= la; op.ma_x[1] ^= la;
    				la = query(root, 0);
    				printf("%d
    ", la);
    			}
    			else
    				break;
    	}
    }
    
    int main()
    {
    	//freopen("F:\rush.txt", "r", stdin);
    	input_data();
    	return 0;
    }


  • 相关阅读:
    298. Binary Tree Longest Consecutive Sequence
    117. Populating Next Right Pointers in Each Node II
    116. Populating Next Right Pointers in Each Node
    163. Missing Ranges
    336. Palindrome Pairs
    727. Minimum Window Subsequence
    211. Add and Search Word
    年底购物狂欢,移动支付安全不容忽视
    成为程序员前需要做的10件事
    全球首推iOS应用防破解技术!
  • 原文地址:https://www.cnblogs.com/AWCXV/p/7632249.html
Copyright © 2011-2022 走看看