hdu-4819-线段树套线段树

http://acm.hdu.edu.cn/showproblem.php?pid=4819

给出一个N*N的矩阵,每次询问一个m*m的子矩阵里的floor((maxv+minv)/2)并把中间的元素修改为这个值。

线段树套线段树,第一层X表示对行建立的线段树,内层表示对Y也就是列建立的线段树。

分别对X和Y建立相应的函数来完成操作,当更新X树的节点时,再更新完当前X的节点的左右儿子之后,回头对X的这个节点对应的Y树进行更新,相当于X的左右儿子里的Y树来更新X的Y树,能理解这一点就很简单了。

  

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 #define pii pair<int,int>
  4 #define mp make_pair
  5 #define LL long long
  6 #define lc (id<<1)
  7 #define rc (id<<1|1)
  8 #define flc (fid<<1)
  9 #define frc (fid<<1|1)
 10 #define mid ((L+R)>>1)
 11 const int maxn=810;
 12 int maxv[maxn<<2][maxn<<2];
 13 int minv[maxn<<2][maxn<<2];
 14 int a[maxn][maxn],N,x1,x2,y1,y2;
 15 void buildY(int,int,int,int,int,int);
 16 void buildX(int id,int L,int R){
 17     if(L==R){
 18         buildY(id,L,R,1,1,N);
 19     }
 20     else{
 21         buildX(lc,L,mid);
 22         buildX(rc,mid+1,R);
 23         buildY(id,L,R,1,1,N);
 24     }
 25 }
 26 void buildY(int fid,int fl,int fr,int id,int L,int R){
 27     if(L==R){
 28         if(fl==fr)maxv[fid][id]=minv[fid][id]=a[fl][L];
 29         else{
 30             maxv[fid][id]=max(maxv[flc][id],maxv[frc][id]);
 31             minv[fid][id]=min(minv[flc][id],minv[frc][id]);
 32         }
 33     }
 34     else{
 35         buildY(fid,fl,fr,lc,L,mid);
 36         buildY(fid,fl,fr,rc,mid+1,R);
 37         maxv[fid][id]=max(maxv[fid][lc],maxv[fid][rc]);
 38         minv[fid][id]=min(minv[fid][lc],minv[fid][rc]);
 39     }
 40 }
 41 pii askY(int fid,int id,int L,int R){
 42     if(L>=y1&&R<=y2){
 43         return mp(maxv[fid][id],minv[fid][id]);
 44     }
 45     else{
 46         if(y2<=mid) return askY(fid,lc,L,mid);
 47         else if(y1>mid) return askY(fid,rc,mid+1,R);
 48         else{
 49             pii pl=askY(fid,lc,L,mid),
 50                 pr=askY(fid,rc,mid+1,R);
 51             return mp(max(pl.first,pr.first),min(pl.second,pr.second));
 52         }
 53     }
 54 }
 55 pii askX(int id,int L,int R){
 56     if(L>=x1&&R<=x2){
 57         return askY(id,1,1,N);
 58     }
 59     else{
 60         if(x2<=mid) return askX(lc,L,mid);
 61         else if(x1>mid) return askX(rc,mid+1,R);
 62         else{
 63             pii pl=askX(lc,L,mid),
 64                 pr=askX(rc,mid+1,R);
 65             return mp(max(pl.first,pr.first),min(pl.second,pr.second));
 66         }
 67     }
 68 }
 69 void updateY(int fid,int fl,int fr,int id,int L,int R,int x,int y,int v){
 70     if(L==R){
 71         if(fl==fr){
 72             maxv[fid][id]=minv[fid][id]=v;
 73         }
 74         else{
 75             maxv[fid][id]=max(maxv[flc][id],maxv[frc][id]);
 76             minv[fid][id]=min(minv[flc][id],minv[frc][id]);
 77         }
 78     }
 79     else{
 80         if(y<=mid){
 81             updateY(fid,fl,fr,lc,L,mid,x,y,v);
 82         }
 83         else{
 84             updateY(fid,fl,fr,rc,mid+1,R,x,y,v);
 85         }
 86         maxv[fid][id]=max(maxv[fid][lc],maxv[fid][rc]);
 87         minv[fid][id]=min(minv[fid][lc],minv[fid][rc]);
 88     }
 89 }
 90 void updateX(int id,int L,int R,int x,int y,int v){
 91     if(L==R){
 92         updateY(id,L,R,1,1,N,x,y,v);
 93     }
 94     else{
 95         if(x<=mid) updateX(lc,L,mid,x,y,v);
 96         else updateX(rc,mid+1,R,x,y,v);
 97         updateY(id,L,R,1,1,N,x,y,v);
 98     }
 99 }
100 int main()
101 {
102     int T,M,i,j,x,y,d;
103     scanf("%d",&T);
104     for(int cas=1;cas<=T;++cas){
105         scanf("%d",&N);
106         for(i=1;i<=N;++i){
107             for(j=1;j<=N;++j){
108                 scanf("%d",&a[i][j]);
109             }
110         }
111         buildX(1,1,N);
112         scanf("%d",&M);
113         printf("Case #%d:\n",cas);
114         while(M--){
115             scanf("%d%d%d",&x,&y,&d);
116             x1=x-d/2,x2=x+d/2,y1=y-d/2,y2=y+d/2;
117             x1=max(x1,1),x2=min(x2,N);
118             y1=max(y1,1),y2=min(y2,N);
119             pii ans=askX(1,1,N);
120             updateX(1,1,N,x,y,(ans.first+ans.second)/2);
121             printf("%d\n",(ans.first+ans.second)/2);
122         }
123     }
124     return 0;
125 }

原文地址:https://www.cnblogs.com/zzqc/p/9941776.html

时间: 2024-10-06 05:43:44

hdu-4819-线段树套线段树的相关文章

HDU - 5390 tree 线段树套字典树 (看题解)

HDU - 5390 看到的第一感觉就是树链剖分 + 线段树套字典树, 感觉复杂度不太对. 其实这种路径其实很特殊, 一个点改变只会影响它儿子到根的路径, 并且这种求最优值问题可以叠加. 所以我们修改的时候对对应dfs序打标记, 询问的时候在线段树上从上往下对每个对应区间求个最优值. 这样还会被卡MLE.. 需要分层优化一下. #pragma GCC optimize(2) #pragma GCC optimize(3) #include<bits/stdc++.h> #define LL l

[BZOJ 1901] Dynamic Rankings 【树状数组套线段树 || 线段树套线段树】

题目链接:BZOJ - 1901 题目分析 树状数组套线段树或线段树套线段树都可以解决这道题. 第一层是区间,第二层是权值. 空间复杂度和时间复杂度均为 O(n log n). 代码 树状数组套线段树 #include <iostream> #include <cstdlib> #include <cstdio> #include <cmath> #include <algorithm> #include <cstring> usin

【vijos】1750 建房子(线段树套线段树+前缀和)

https://vijos.org/p/1750 是不是我想复杂了.... 自己yy了个二维线段树,然后愉快的敲打. 但是wa了两法.......sad 原因是在处理第二维的更新出现了个小问题,sad. void pushup1(int x) { for1(i, 1, mm<<2) mn[x][i]=min(mn[lc][i], mn[rc][i]); } 这里注意是mm*4...我该好好想想了..这是在dbg的时候找出来的问题.sad. 我觉得很奇怪,线段树的底层节点一共就mm个,那么整棵树

【bzoj4785】[Zjoi2017]树状数组 线段树套线段树

题目描述 漆黑的晚上,九条可怜躺在床上辗转反侧.难以入眠的她想起了若干年前她的一次悲惨的OI 比赛经历.那是一道基础的树状数组题.给出一个长度为 n 的数组 A,初始值都为 0,接下来进行 m 次操作,操作有两种: 1 x,表示将 Ax 变成 (Ax + 1) mod 2. 2 l r,表示询问 sigma(Ai) mod 2,L<=i<=r 尽管那个时候的可怜非常的 simple,但是她还是发现这题可以用树状数组做.当时非常young 的她写了如下的算法: 1: function Add(x

ZJOI 2017 树状数组(线段树套线段树)

题意 http://uoj.ac/problem/291 思路 不难发现,九条カレン醬所写的树状数组,在查询区间 \([1,r]\) 的时候,其实在查询后缀 \([r,n]\) :在查询 \([l,r](l\neq1)\) 的时候,则是在查询 \([l-1,r-1]\) .那么在查询 \([1,r]\) 的时候,只需要询问 \(r\) 的前后缀异或是否相等:在查询 \([l,r](l\neq 1)\) 的时候,只需要询问 \(a[l-1],a[r]\) 是否相等. 考虑 \(O(n^2)\) 的

BZOJ 3217 ALOEXT 替罪羊树套Trie树

题目大意:维护一个序列,支持以下操作: 1.在某个位置插入一个数 2.删除某个位置上的数 3.修改某个位置上的数 4.求某段区间中的次大值与区间中另一个数的异或值的最大值 强制在线 替罪羊树套Trie树...终于尼玛A了...7.4KB的大代码啊- - 插入和修改同带插入区间k小值 删除要打标记不能直接删 删除的时候注意 删除导致的不平衡不要重建 否则复杂度无法保证 因此每个节点维护一个max_size代表历史size最大值 判断不平衡时用这个变量来判断即可 注意访问替罪羊树的时候一定要判断当前

【bzoj3217】ALOEXT 替罪羊树套Trie树

题目描述 taorunz平时最喜欢的东西就是可移动存储器了……只要看到别人的可移动存储器,他总是用尽一切办法把它里面的东西弄到手. 突然有一天,taorunz来到了一个密室,里面放着一排可移动存储器,存储器里有非常珍贵的OI资料……不过比较特殊的是,每个存储器上都写着一个非负整数.taorunz很高兴,要把所有的存储器都拿走(taorunz的智商高达500,他一旦弄走了这里的所有存储器,在不久到来的AHOI和NOI中……你懂的).不过这时有一个声音传来:“你只能拿走这里的一个存储器,而且还不能直

HDU 4819:Mosaic(线段树套线段树)

http://acm.hdu.edu.cn/showproblem.php?pid=4819 题意:给出一个矩阵,然后q个询问,每个询问有a,b,c,代表(a,b)这个点上下左右c/2的矩形区域内的(最大值+最小值)/2是多少,并且将(a,b)的值替换成这个答案. 思路:很久以前被暴力跑过去的一道题,今天怎么交也过不去...果然是人品爆发了. 学了一下树套树,一开始觉得挺容易理解,但是后面PushUp那里挺难懂的(对我来说). 我的理解: 对于每个线段树的结点开一棵线段树,即tree[x][y]

BZOJ 3065 带插入区间K小值 替罪羊树套线段树

题目大意:带插入,单点修改的区间k小值在线查询. 思路:本年度做过最酸爽的题. 树套树的本质是一个外层不会动的树来套一个内层会动(或不会动)的树.两个树的时间复杂度相乘也就是差不多O(nlog^2n)左右.但是众所周知,高级数据结构经常会伴有庞大的常数,所以一般来说树套树的常数也不会小到哪去.所以在做这种题的时候先不要考虑常数的问题... 为什么要用替罪羊树呢?因为一般的平衡树都是会动的,这就很难办了.外层的树动了之后,内层的树肯定也是会动的.很显然,一般的二叉平衡树会经常会旋转,这样在动外层的