AT_arc047_d [ARC047D] ナナメクエリ 题解

本文迁移自洛谷原文

link

题目大意:

有一个 )的正方形矩阵,初始全部为 ,下标从 开始。

)次操作:

  • 将所有满足 的点 的值加上

  • 将所有满足 的点 的值加上

  • 查询所有满足 的点 的最大值,并求出值为最大值的点的个数。

部分分:

题解:

我们考虑维护两个数组 ,其中 表示所有满足 的点加的和, 表示所有满足 的点加的和。

对于一个点 ,他的值就是 ,所以我们维护 就可以知道全矩阵的值了, 操作的复杂度都为

关键在于这个询问。

我们可以枚举所有可能的 (就是 的值),那么可以发现,那些在 已知的条件下可行的 就是连续的一些奇数或者偶数。用数据结构维护可以做到 ,得到部分分。

再继续考虑。

考虑特殊化,查询的是一个正方形。

如果我们从小到大枚举所有的 ,且枚举的时候让 (就是按照 的顺序枚举),可以发现每次只会新增两个可能的 ,不会变少,所以我们只要暴力用新增的两个 更新就行了。

同理,我们再按照 的顺序枚举,两种情况合并后就是答案了。

再考虑把查询一般化为长方形,则可以按照类似辗转相减法的方法每次割出最大的正方形去查询,然后合并所有的答案,可以证明单次询问复杂度为 ,故总时间复杂度为


Code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
#include<bits/stdc++.h>
using namespace std;
const int mxn=1e4+9;
const int base=5003;
int n,q,s1[mxn],s2[mxn];
inline pair<int,int> G(pair<int,int> x,pair<int,int> y){
if(x.first!=y.first){
if(x.first>y.first)return x;
else return y;
}
x.second+=y.second;
return x;
}
inline pair<int,int> go(int a,int b,int c,int d){
int cur,cnt,len;
pair<int,int>rt={-1145141919,0};
cur=-1145141919,cnt=0,len=-2;
for(int sum1=a+b,sum2=c+d;sum1<=a+d;sum1+=2,sum2-=2){ //第一类
len+=2;
if(s2[a-b+base-len]>cur)cur=s2[a-b+base-len],cnt=1;
else if(s2[a-b+base-len]==cur)++cnt;
if(len!=0){
if(s2[a-b+base+len]>cur)cur=s2[a-b+base+len],cnt=1;
else if(s2[a-b+base+len]==cur)++cnt;
}
if(s1[sum1]+cur>rt.first){
rt.first=s1[sum1]+cur;
rt.second=cnt;
}else if(s1[sum1]+cur==rt.first){
rt.second+=cnt;
}
if(sum1!=sum2){
if(s1[sum2]+cur>rt.first){
rt.first=s1[sum2]+cur;
rt.second=cnt;
}else if(s1[sum2]+cur==rt.first){
rt.second+=cnt;
}
}
}
len=-1,cnt=0,cur=-1145141919;
for(int sum1=a+b+1,sum2=c+d-1;sum1<=a+d;sum1+=2,sum2-=2){ //第二类
len+=2;
if(s2[a-b+base-len]>cur)cur=s2[a-b+base-len],cnt=1;
else if(s2[a-b+base-len]==cur)++cnt;
if(len!=0){
if(s2[a-b+base+len]>cur)cur=s2[a-b+base+len],cnt=1;
else if(s2[a-b+base+len]==cur)++cnt;
}
if(s1[sum1]+cur>rt.first){
rt.first=s1[sum1]+cur;
rt.second=cnt;
}else if(s1[sum1]+cur==rt.first){
rt.second+=cnt;
}
if(sum1!=sum2){
if(s1[sum2]+cur>rt.first){
rt.first=s1[sum2]+cur;
rt.second=cnt;
}else if(s1[sum2]+cur==rt.first){
rt.second+=cnt;
}
}
}
return rt;
}
inline auto solve(int a,int b,int c,int d){//割成极大正方形
if(c-a==d-b)return go(a,b,c,d);
int l=min(c-a,d-b);
if(c-a>d-b){
pair<int,int> rt=go(a,b,a+l,b+l);
rt=G(rt,solve(a+l+1,b,c,d));
return rt;
}else{
pair<int,int> rt=go(a,b,a+l,b+l);
rt=G(rt,solve(a,b+l+1,c,d));
return rt;
}
}
int main(){
ios_base::sync_with_stdio(false);
cin.tie(0),cout.tie(0);
cin>>n>>q;
for(;q--;){
int tp,a,b,c,d;
cin>>tp;
if(tp==1){
cin>>a>>b>>c;
for(int i=a;i<=b;++i)s1[i]+=c;
}
if(tp==2){
cin>>a>>b>>c;
a+=base,b+=base;
for(int i=a;i<=b;++i)s2[i]+=c;
}
if(tp==3){
cin>>a>>b>>c>>d;
auto p=solve(a,c,b,d);
cout<<p.first<<' '<<p.second<<'\n';
}
}
}