CheaSim Blog

IDEA 配置struts2+tomcat

使用IDEA配置Struts2

Struts2版本选择

由于笔者学校环境有限,教的是版本是2.3版本,所以先去官网上下载2.3的最新版本。

[HDOJ5592] ZYB's Premutation

[HDOJ5592] ZYB’s Premutation

题意

ZYB有一个序列所有的逆序数前缀和,$a_1,a_2,a_3,…,a_n$,他们各个都表示从1到$i$的逆序数的前缀和。

题解

树状数组+二分

首先我们可以倒着看,对于最后一个数字,他的逆序数减前面的逆序数就代表着前面大于他的个数。所以我们就可以把问题转化为,已知数字$a_i$在前$i$个中的位置,求$a_i是多少。

我们可以用树状数组来维护,$sum(i)$表示到$i$代表着$i$是第几个数字,每当一个数字用过之后,他后面的数字都要-1,因为他们的排序相当于减少了一个,第四个数字变成第三个数字。


+n 没有想到这个序列是单调的,所以可以二分。居然想的是怎么让整个数组往前挪。

ac代码

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
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for(int i=(a);i<(n);i++)
#define per(i,a,n) for(int i=(n-1);i>=(a);i--)
#define fi first
#define se second
typedef pair <int,int> pII;
typedef long long ll;
const int INF = 0x3f3f3f3f;
//head
const int maxn = 5e4 + 1000;
int T,n;
int a[maxn],b[maxn],ans[maxn],bit[maxn];
int lowbit(int x){
return x&-x;
}
int add(int x,int val){
for(int i=x;i<=n;i+=lowbit(i)){
bit[i] += val;
}
}
int query(int x){
int s = 0;
for(int i=x;i;i-=lowbit(i)){
s += bit[i];
}
return s;
}
int solve(int l,int r,int x){
int ans = 0;
while(l<=r){
int mid = l+r>>1;
int temp = query(mid);
if(temp >= x){
r = mid-1;
ans = mid;
}else{
l = mid+1;
}
}
return ans;
}
int main(){
#ifdef LOCAL
freopen("2.in","r",stdin);
#endif
scanf("%d",&T);
while(T--){
scanf("%d",&n);
memset(bit,0,sizeof(bit));
memset(ans,0,sizeof(ans));
rep(i,1,n+1) add(i,1);
rep(i,1,n+1) scanf("%d",a+i);
rep(i,1,n+1) b[i] = a[i] - a[i-1];
per(i,1,n+1){
int pos = i-b[i];
ans[i] = solve(1,n,pos);
add(ans[i],-1);
}
rep(i,1,n+1){
printf("%d%c",ans[i],i==n?'\n':' ');
}
}
return 0;
}

The 2018 ACM-ICPC Asia Qingdao Regional Contest, Online

The 2018 ACM-ICPC Asia Qingdao Regional Contest, Online(青岛网络赛)

B.Red Black Tree

题意

题解

ac代码

J.Press the Button

题意

题解

ac代码

H Traveling on the Axis

题意

BOB走在$[1,n]$的路上,每两个点中间都有一个红绿灯,每一秒钟,

  • BOB先观察红绿灯是否绿,绿就走,红就停。
  • 红灯变绿,绿灯变红

$t(p,q)$就是$p$走到$q所需要的时间。

问: BOB从 $\sum^{n-1}{p=0} \sum{q=p+1}^nt(p,q)$的时间总和。

题解

对于第$i$个单独的红绿灯我们可以证明他对答案的贡献是

​ $(i)(len-i+1)(t(i))$

我们对于两个灯进行分析。

01 第一个零要2s,第二个一要1s

10 第一个一要1s,第二个零要1s

00 第一个零要2s,第二个一要2s

11 第一个一要1s,第二个一要2s

综上可以发现,

  • 该灯初始为0,那么他当头的时候贡献为2,如果不当头那么他的贡献就为1,除非跟前者相同。
  • 该灯初始为1,那么他和前一个灯相同时贡献为2,就算变成0了,不在头上的话贡献也为1.

我他妈sb了,不应该看着一段一段的区间,应该把红绿灯作为每一次状态的扩展,从红绿灯这$n$个出发开始计算,不应该考虑一个一个的单位为1的区间。

AC代码

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
// CSL 代码
#include <bits/stdc++.h>
using namespace std;
const int N = 1 << 17;
char s[N];
typedef long long ll;
int main()
{
int T;
scanf("%d", &T);
while (T--)
{
scanf("%s", s);
ll ans = 0;
int n = strlen(s);
for (int i = 0; i < n; i++) ans += 1LL * (i + 1) * (n - i);
for (int i = 0; s[i]; i++)
{
if (s[i] == '0') ans += n - i;
if (i && (s[i] == s[i - 1])) ans += 1LL * i * (n - i);
//要跟包含前者的可能,要两个相同才能这么加。
}
printf("%lld\n", ans);
}
}
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
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for(int i=(a);i<(n);i++)
#define per(i,a,n) for(int i=(n-1);i>=(a);i--)
#define fi first
#define se second
typedef pair <int,int> pII;
typedef long long ll;
const int INF = 0x3f3f3f3f;
//head

const int maxn = 1e5 + 10;
char s[maxn];
int main(){
#ifdef LOCAL
freopen("h.in","r",stdin);
#endif
int T;scanf("%d",&T);
while(T--){
scanf("%s",s);
int len = strlen(s);
ll ans = 0; ll w = 0;
if(s[0]=='1') ans = w = 1;
else ans = w = 2;
rep(i,1,len){
if(s[i]==s[i-1]) w += i*2;
else w += i*1;
if(s[i]=='1') w += 1;
else w += 2;
ans += w;
}
printf("%lld\n",ans);
}

return 0;
}

reference:

https://blog.csdn.net/tianyizhicheng/article/details/82728350

概率dp入门

概率dp

概率dp有两种题型,一种是求概率一种是求期望。

来结合一下题目

Aeroplane chess

题意

一个人在一条线上掷骰子,在线上有类似飞行棋的可以直接到达某个点的特殊点,问从$0$到$n$掷骰子次数的数学期望是多少?

题解

期望dp,dp最重要的就是从一个已知的最优状态转化到另一个最优状态。

为什么期望要反着求呢,因为你并不知道$dp[0]$这个点的值,因为我们定义$dp[x]$为$x$点到$n$点的掷骰子数的数学期望。而$dp[n]$的数学期望我们是知道的,是0,因为已经在$n$点了。之后我们倒推前面点的数学期望,因为你骰子是6面,从一个点可以到后面的六个点并且是等概率的,所以

$dp[i] = \sum_{j=i+1}^{i+6}dp[j]/6+1$

而且如果是特殊的飞行点,那么他的数学期望直接就是他的到的点的数学期望。

+2:没有从n-1开始,居然sb到从n开始计算。

AC代码

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
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for(int i=(a);i<(n);i++)
#define per(i,a,n) for(int i=(n-1);i>=(a);i--)
#define fi first
#define se second
#define pb push_back
typedef pair <int,int> pII;
typedef long long ll;
const int INF = 0x3f3f3f3f;
//head
int n,m;
const int maxn = 1e5 + 10;
double dp[maxn];
int nxt[maxn];
int main(){
#ifdef LOCAL
freopen("11.in","r",stdin);
#endif
while(scanf("%d%d",&n,&m) && (m||n)){
rep(i,0,n+1) dp[i] = 0.0,nxt[i] = 0;
rep(i,0,m){
int x,y;scanf("%d%d",&x,&y);
nxt[x] = y;
}
per(i,0,n){
if(nxt[i]){
dp[i] = dp[nxt[i]];
}else{
double sum = 0.0;
rep(j,1,6+1){
if(i+j<=n){
sum+=dp[i+j];
}
}
dp[i] = sum/6.0+1.0;
}
}
printf("%0.4f\n",dp[0]);
}
return 0;
}

B - Discovering Gold

题意

跟上面的差不多,就是求期望。

题解

跟上面基本相似。

AC代码

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
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for(int i=(a);i<(n);i++)
#define per(i,a,n) for(int i=(n-1);i>=(a);i--)
#define fi first
#define se second
typedef pair <int,int> pII;
typedef long long ll;
const int INF = 0x3f3f3f3f;
//head
const int maxn = 110;
int T,n;
double dp[maxn];
int main(){
#ifdef LOCAL
freopen("2.in","r",stdin);
#endif
scanf("%d",&T);
rep(test_case,1,T+1){
scanf("%d",&n);
rep(i,1,n+1) cin>>dp[i];
per(i,1,n){
double sum = 0.0;
double cnt = 0;
rep(j,i+1,i+7){
if(j<=n) sum+=dp[j],cnt++;
}
dp[i] += sum/cnt;
}
printf("Case %d: %0.9f\n",test_case,dp[1]);
}

return 0;
}

快读模板

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
template <typename T>  
inline bool read (T &ret) {
char c;
int sgn;
if (c = getchar(), c == EOF) return 0; //EOF
while (c != '-' && (c < '0' || c > '9') ) {
if((c = getchar()) == EOF) return 0;
}
sgn = (c == '-') ? -1 : 1;
ret = (c == '-') ? 0 : (c - '0');
while (c = getchar(), c >= '0' && c <= '9') ret = ret * 10 + (c - '0');
ret *= sgn;
return 1;
}
template<typename T>
void print(T x) {
static char s[33], *s1; s1 = s;
if (!x) *s1++ = '0';
if (x < 0) putchar('-'), x = -x;
while(x) *s1++ = (x % 10 + '0'), x /= 10;
while(s1-- != s) putchar(*s1);
}
template<typename T>
void println(T x) {
print(x); putchar('\n');
}

ACM-ICPC 2018 徐州赛区网络预赛

ACM-ICPC 2018 徐州赛区网络预赛

A. Hard to prepare

题意

$n$个人围成环,每个人可以选择$[0,2^k-1]$中的一个数字,要求相邻两人不能同或为0。

题解

递归。

可以YY出,第一个人有$2^k$种选择,之后第2到第$n-1$个人有$2^k-1$种选择,最后一个人可能可以选$2^k-2$,也可能可以选$2^k-1$。这取决于倒数第二个人是否跟第一个人选一样的。这时候我们就可以加上如果第一个人和倒数第二个人选择相同,并且,最后一个人多选了那$2^k-1-(2^k-2)$种,那么他们三个点变成一个点来选择了。

AC代码

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
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for(int i=(a);i<(n);i++)
#define per(i,a,n) for(int i=(n-1);i>=(a);i--)
#define fi first
#define se second
typedef pair <int,int> pII;
typedef long long ll;
const int INF = 0x3f3f3f3f;
//head
int n,k;
const ll mod = 1e9+7;
ll pow3(ll a,ll b){
ll ans = 1;
while(b){
if(b&1) ans = ans*a%mod;
a = a*a%mod;
b>>=1;
}
return ans;
}
ll k2,kk2,kk1;
ll solve(int n,int k){
if(k==1) return 2;
if(n==1) return k2;
if(n==2) return k2*kk1%mod;
ll res = (k2*kk2%mod)*pow3(kk1,n-2)%mod;
res = (res+solve(n-2,k))%mod;
return res;
}
int main(){
#ifdef LOCAL
freopen("4.in","r",stdin);
#endif
int T;scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&k);
k2 = pow3(2,k);
kk1 = (k2-1+mod)%mod;
kk2 = (k2-2+mod)%mod;
printf("%lld\n",solve(n,k));
}

return 0;
}

B.BE,GE or NE

题意

两个人玩游戏,给出$[0,3]$个选项和一个$m$初始值,两个人依次选择,有以下三种选择

  • 选择将值$+a$
  • 选择将值$-b$
  • 选择将值倒过来 $m=-m$

两个人一个想将值变大,一个想让值变小,两个人都知晓所有情况和选项,在最优情况下,问谁赢。

题解

博弈论dp+记忆化搜索

因为数据量很小,范围也在200之间,所以记忆化状态回复的很多。

$dp[pos][val]$表示在pos位置数值是val,之后dp代表的是最优可以赢还是输还是平,分别用2,1,0代表。

之后对于边界值要处理一下。数组存不了负值,我们统一加100处理。


妈的。我看到这个以为是纯博弈论直接人傻了。之后想着能不能记忆化搜索,但是看到$n=1000$还以为他喵的会爆,但是这道题的情况限制在范围$-100到100$,所以情况很少。所以可以直接记忆化,不过对于答案的选择和状态转移我可能还是不会太轻松地做出来,带int的dfs我还是不怎么熟悉,这按道理应该是算是博弈论dp了。从最优状态转移到最优状态。

AC代码

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
#include <bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for (int i=a;i<n;i++)
#define per(i,a,n) for (int i=n-1;i>=a;i--)
#define pb push_back
#define mp make_pair
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define SZ(x) ((int)(x).size())
typedef vector<int> VI;
typedef long long ll;
typedef pair<int,int> PII;
const ll mod=1000000007;
ll powmod(ll a,ll b) {ll res=1;a%=mod; assert(b>=0); for(;b;b>>=1){if(b&1)res=res*a%mod;a=a*a%mod;}return res;}
ll gcd(ll a,ll b) { return b?gcd(b,a%b):a;}
// head
int n,m,k,l;
const int maxn = 1e3 + 10;
int a[maxn],b[maxn],c[maxn];
int dp[maxn][220];
// op
int dfs(int pos,int val){
if(pos == n){
if(val >= k){
return 2;
}else if(val > l){
return 1;
}else{
return 0;
}
}
if(dp[pos][val] != -1) return dp[pos][val];
if(pos%2==0){
int res = 0;
int mmin = min(200,val+a[pos]);
int mmax = max(0,val-b[pos]);
if(a[pos]) res = max(res,dfs(pos+1,mmin));
if(b[pos]) res = max(res,dfs(pos+1,mmax));
if(c[pos]) res = max(res,dfs(pos+1,200-val));
return dp[pos][val] = res;
}else{
int res = 2;
int mmin = min(200,val+a[pos]);
int mmax = max(0,val-b[pos]);
if(a[pos]) res = min(res,dfs(pos+1,mmin));
if(b[pos]) res = min(res,dfs(pos+1,mmax));
if(c[pos]) res = min(res,dfs(pos+1,200-val));
return dp[pos][val] = res;
}
}
int main(){
#ifdef LOCAL
freopen("b.in","r",stdin);
#endif // LOCAL
rep(i,0,maxn) rep(j,0,220) dp[i][j] = -1;
scanf("%d%d%d%d",&n,&m,&k,&l);
l += 100; k += 100; m += 100;
rep(i,0,n){
scanf("%d%d%d",a+i,b+i,c+i);
}
int op = dfs(0,m);
if(op==2) puts("Good Ending");
else if(op==1) puts("Normal Ending");
else puts("Bad Ending");
return 0;
}

[hdoj1540]Tunnel Warfare

Tunnel Warfare

题意

在一条线上有二种操作

  • 删掉一个点
  • 恢复一个点

求某一个点和与之相连点的个数。

题解

线段树设左右标志或者是树状数组二分

HDOJ可以线段树+二分。


Cnm hdoj 多组数据不给提示

如果是树状数组500ms,线段树+二分1500ms。

POJ卡了线段树+二分。HDOJ没有写多组输入害得我WA成sb了。

垃圾HDOJ还造假数据,毁坏多个碉堡。也是服了。

WA代码

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
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for(int i=(a);i<(n);i++)
#define per(i,a,n) for(int i=(n-1);i>=(a);i--)
#define fi first
#define se second
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
typedef pair <int,int> pII;
typedef long long ll;
const int INF = 0x3f3f3f3f;
//head
const int maxn = 5e4+10;
int sum[maxn<<3],vis[maxn],last[maxn];
int n,q;
void pushup(int rt){
sum[rt] = sum[rt<<1]+sum[rt<<1|1];
}
void build(int l,int r,int rt){
if(l==r){
sum[rt] = 1;
return;
}
int mid = l+r>>1;
build(lson); build(rson);
pushup(rt);
}
void update(int val,int p,int l,int r,int rt){
if(l==r && l==p){
sum[rt] = val;
return;
}
int mid = l+r>>1;
if(p <= mid) update(val,p,lson);
if(mid < p) update(val,p,rson);
pushup(rt);
}
int query(int L,int R,int l,int r,int rt){
if(L<=l && r<=R){
return sum[rt];
}
int mid = l+r>>1;
int ans = 0;
if(L <= mid) ans += query(L,R,lson);
if(mid < R) ans += query(L,R,rson);
return ans;
}
bool check(int l,int r){
if(query(l,r,1,n,1) == r-l+1) return true;
return false;
}
int solve1(int l,int r,int rt){
int mid;int st = n;
while(l<=r){
mid = l+r>>1;
if(check(mid,r)) r = mid-1,st = mid;
else l = mid+1;
}
return st;
}
int solve2(int l,int r,int rt){
int mid ;int ed = n;
while(l<=r){
mid = l+r>>1;
if(check(l,mid)) l = mid+1,ed = mid;
else r = mid-1;
}
return ed;
//cout<<ed<<' ';
}
int main(){
#ifdef LOCAL
freopen("2.in","r",stdin);
#endif
while(~scanf("%d%d",&n,&q)){
build(1,n,1);
rep(i,1,n+1) vis[i] = 1;
int top = 0;
while(q--){
char op[20];
scanf("%s",op);
if(op[0] == 'D'){
int x; scanf("%d",&x);
update(0,x,1,n,1);
last[top++] = x;
}else if(op[0] == 'R'){
int x =last[--top];
update(1,x,1,n,1);
}else{
int x;scanf("%d",&x);
if(query(x,x,1,n,1)==0){
puts("0");
continue;
}
printf("%d\n",solve2(x,n,x)-solve1(1,x,x)+1);
}
}
}

return 0;
}

AC代码

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
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for(int i=(a);i<(n);i++)
#define per(i,a,n) for(int i=(n-1);i>=(a);i--)
#define fi first
#define se second
typedef pair <int,int> pII;
typedef long long ll;
const int INF = 0x3f3f3f3f;
//head
int n,m;
const int maxn = 5e4+20;
int bit[maxn];
int lowbit(int x){
return x&-x;
}
int query(int x){
int ans = 0;
for(int i = x;i;i-=lowbit(i)){
ans += bit[i];
}
return ans;
}
int query(int l,int r){
return query(r)-query(l-1);
}
void add(int x,int val){
for(int i=x;i<=n;i+=lowbit(i)){
bit[i] += val;
}
}
int solve_left(int l,int r){
int mid = l+r>>1;int ans = r;
while(l<=r){
mid = l+r>>1;
if(query(mid,r)==r-mid+1) r = mid-1,ans = mid;
else l = mid+1;
}
return ans;
}
int solve_right(int l,int r){
int mid,ans = l;
while(l<=r){
mid = l+r>>1;
if(query(l,mid)==mid-l+1) l=mid+1,ans = mid;
else r = mid-1;
}
return ans;
}
int vis[maxn];
int main(){
#ifdef LOCAL
freopen("2.in","r",stdin);
#endif
while(scanf("%d%d",&n,&m)!=EOF){
stack<int> st;
memset(bit,0,sizeof(bit));
memset(vis,0,sizeof(vis));
rep(i,1,n+1) add(i,1);
while(m--){
char op[20];scanf("%s",op);
if(op[0]=='D'){
int x;scanf("%d",&x);
st.push(x);
if(vis[x]) continue;
vis[x] = 1;
add(x,-1);
}else if(op[0]=='Q'){
int x;scanf("%d",&x);
if(query(x,x)==0) puts("0");
else printf("%d\n",solve_right(x,n)-solve_left(1,x)+1);
}else{
add(st.top(),1);
vis[st.top()] = 0;
st.pop();
}
}
}

return 0;
}

[hdoj4614]Vases and Flowers

Vases and Flowers

题意

Alice去一排$n$的花盆中种花,有两种操作

  • 从$a$开始种花,如果该花盆有花就跳到下一个花盆。直到没有花种或者到了$n$盆
  • $[a,b]$区间的所有花都扔掉。

询问

  • 1操作中开始种花的盆和停止种花的盆
  • 2操作中丢掉的花

题解

线段树,$sum$表示花的个数,用$lazy$来懒惰标记。


妈的,我线段树还是不够熟悉,居然使用了$update(p,n,1)$这样子的形式,以为每个区间的$rt$都是随机的,其实线段树的区间都是固定的,你只能通过$lson,rson$来寻找每一个区间,不能自己xjb改区间。

寻找p开始位置的时候,需要思考一下。image一下中点和左端与p的关系就好了。

AC代码

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
103
104
105
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for(int i=(a);i<(n);i++)
#define per(i,a,n) for(int i=(n-1);i>=(a);i--)
#define fi first
#define se second
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
typedef pair <int,int> pII;
typedef long long ll;
const int INF = 0x3f3f3f3f;
//head
const int maxn = 5e5 + 10;
int m,n,T;
int now,ed,st;
bool flag = 0;
int sum[maxn<<2],lazy[maxn<<2];
void pushup(int rt){
sum[rt] = sum[rt<<1] + sum[rt<<1|1];
}
void pushdown(int rt,int len){
if(lazy[rt] == 0){
lazy[rt<<1] = lazy[rt<<1|1] = 0;
sum[rt<<1] = sum[rt<<1|1] = 0;
lazy[rt] = -1;
}
if(lazy[rt] == 1){
lazy[rt<<1] = lazy[rt<<1|1] = 1;
sum[rt<<1] = len-len/2;
sum[rt<<1|1] = len/2;
lazy[rt] = -1;
}
}
void build(int l,int r,int rt){
lazy[rt] = -1;
if(l==r){
sum[rt] = 0;
return ;
}
int mid = l+r>>1;
build(lson);build(rson);
pushup(rt);
}
void update(int p,int l,int r,int rt){
if(now == 0) return;
if(r-l+1 == sum[rt]) return;
if(sum[rt] == 0 && now >= r-l+1 && l>=p){
sum[rt] = r-l+1;
now -= (r-l+1);
lazy[rt] = 1;
if(!flag) st = l,flag = 1,ed = r;
else ed = r;
return;
}
pushdown(rt,r-l+1);
int mid = l+r>>1;
if(p <= mid) update(p,lson);
update(p,rson);
pushup(rt);
}
void update(int L,int R,int l,int r,int rt){
if(L<=l && r<=R){
now += sum[rt];
sum[rt] = 0;
lazy[rt] = 0;
return;
}
pushdown(rt,r-l+1);
int mid = l+r>>1;
if(L <= mid) update(L,R,lson);
if(mid < R) update(L,R,rson);
pushup(rt);
}
int main(){
#ifdef LOCAL
freopen("1.in","r",stdin);
#endif
scanf("%d",&T);
while(T--){
scanf("%d%d",&n,&m);
build(1,n,1);
rep(i,0,m){
int op,a,b;
scanf("%d%d%d",&op,&a,&b);
if(op==1){
a++;
now = b;st = ed = a; flag = 0;
update(a,1,n,1);
if(now==b){
puts("Can not put any one.");
}else{
ed--;st--;
printf("%d %d\n",st,ed);
}
}else{
now = 0;
a++;b++;
update(a,b,1,n,1);
printf("%d\n",now);
}
}
puts("");
}
return 0;
}

[kuangbin带你飞7]线段树

kuangbin带你飞7

前言

作为一名acm选手,不能连线段树都不会,练就完事了。而且我越发觉得在赛场上不能卡机,中档题才是区分牌子的题目。只有慢慢思索的题目才能真正地提高自己,立下一个flag,每十天完成一个kuangbin专题。现在时间9/6。必须在9/16完成这个线段树专题,就算是困死也得完成。

感想

  1. 左右区间还是注意一下,保不准出题人恶趣味。

  2. 初始化不能想当然$n$多大树多大,有可能他是一个范围,$n$只是代表着式子的个数罢了。

  3. 数组居然还是又一次忘记开4倍。

  4. lazy数组忘记初始化,或者lazy可以为0但是还是初始化为0了。

A.敌兵布阵

题意

这如果我没有记错,应该是人生中第一个线段树题目,很是经典。单点修改,区间查询。

题解

线段树。

AC代码

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
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for(int i=(a);i<(n);i++)
#define per(i,a,n) for(int i=(n-1);i>=(a);i--)
#define fi first
#define se second
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
typedef pair <int,int> pII;
typedef long long ll;
const int INF = 0x3f3f3f3f;
//head
const int maxn = 5e4 + 10;
int T,n;
int sum[maxn<<2],lazy[maxn<<2],a[maxn];
void pushup(int rt){
sum[rt] = sum[rt<<1] + sum[rt<<1|1];
}
void pushdown(int rt,int len){
if(lazy[rt]){
lazy[rt<<1] += lazy[rt];
lazy[rt<<1|1] += lazy[rt];
sum[rt<<1] += lazy[rt]*(len/2);
sum[rt<<1|1] += lazy[rt]*(len-len/2);
lazy[rt] = 0;
}
}
void build(int l,int r,int rt){
lazy[rt] = 0;
if(l==r){
sum[rt] = a[l];
return ;
}
int mid = l+r>>1;
build(lson);build(rson);
pushup(rt);
}
void update(int val,int L,int R,int l,int r,int rt){
if(L<=l && r<=R){
lazy[rt] += val;
sum[rt] += val*(r-l+1);
return ;
}
pushdown(rt,r-l+1);
int mid = l+r>>1;
if(L <= mid) update(val,L,R,lson);
if(mid < R) update(val,L,R,rson);
pushup(rt);
}
int query(int L,int R,int l,int r,int rt){
if(L<=l && r<=R) return sum[rt];
pushdown(rt,r-l+1);
int mid = l+r>>1;
int ans = 0;
if(L <= mid) ans += query(L,R,lson);
if(mid < R) ans += query(L,R,rson);
return ans;
}
int main(){
#ifdef LOCAL
freopen("a.in","r",stdin);
#endif
scanf("%d",&T);
rep(test_case,1,T+1){
scanf("%d",&n);
rep(i,1,n+1) scanf("%d",a+i);
build(1,n,1);
char op[20];
printf("Case %d:\n",test_case);
while(scanf("%s",op) && op[0]!='E'){
if(op[0]=='A' || op[0] =='S'){
int l,val;scanf("%d%d%d",&l,&val);
if(op[0] == 'A') update(val,l,l,1,n,1);
else update(-val,l,l,1,n,1);
}else{
int l,r;scanf("%d%d",&l,&r);
printf("%d\n",query(l,r,1,n,1));
}
}
}

return 0;
}

B.I Hate It

题意

单点修改,区间最值。

题解

线段树。

AC代码

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
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for(int i=(a);i<(n);i++)
#define per(i,a,n) for(int i=(n-1);i>=(a);i--)
#define fi first
#define se second
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
typedef pair <int,int> pII;
typedef long long ll;
const int INF = 0x3f3f3f3f;
//head
const int maxn = 2e5 + 10;
int n,m;
int mmax[maxn<<2],a[maxn];
void pushup(int rt){
mmax[rt] = max(mmax[rt<<1],mmax[rt<<1|1]);
}
void build(int l,int r,int rt){
if(l==r){
mmax[rt] = a[l];
return;
}
int mid = l+r>>1;
build(lson);build(rson);
pushup(rt);
}
void update(int val,int p,int l,int r,int rt){
if(l==r && l==p){
mmax[rt] = val;
return;
}
int mid = l+r>>1;
if(p <= mid) update(val,p,lson);
if(mid < p) update(val,p,rson);
pushup(rt);
}
int query(int L,int R,int l,int r,int rt){
if(L<=l && r<=R) return mmax[rt];
int mid = l+r>>1;
int ans = 0;
if(L <= mid) ans = max(ans,query(L,R,lson));
if(mid < R) ans = max(ans,query(L,R,rson));
return ans;
}
int main(){
#ifdef LOCAL
freopen("b.in","r",stdin);
#endif
while(~scanf("%d%d",&n,&m)){
rep(i,1,n+1) scanf("%d",a+i);
build(1,n,1);
rep(i,0,m){
char op[20];int x,y;
scanf("%s%d%d",op,&x,&y);
if(op[0] == 'Q'){
printf("%d\n",query(x,y,1,n,1));
}else{
update(y,x,1,n,1);
}
}
}
return 0;
}

C - A Simple Problem with Integers

题意

区间查询,区间修改。

题解

线段树

lazy需也要开两倍

AC代码

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
#include<cstring>
#include<stdio.h>
#include<cmath>
#include<algorithm>
#include<iostream>
using namespace std;
#define rep(i,a,n) for(int i=(a);i<(n);i++)
#define per(i,a,n) for(int i=(n-1);i>=(a);i--)
#define fi first
#define se second
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
typedef pair <int,int> pII;
typedef long long ll;
const int INF = 0x3f3f3f3f;
//head
const int maxn = 1e5 + 10;
ll sum[maxn<<2],a[maxn],lazy[maxn<<2];
int n,q;
void pushup(int rt){
sum[rt] = sum[rt<<1]+sum[rt<<1|1];
}
void pushdown(int rt,ll len){
if(lazy[rt]){
lazy[rt<<1] += lazy[rt];
lazy[rt<<1|1] += lazy[rt];
sum[rt<<1] += lazy[rt]*(len-len/2);
sum[rt<<1|1] += lazy[rt]*(len/2);
lazy[rt] = 0;
}
}
void build(int l,int r,int rt){
if(l==r){
sum[rt] = a[l];
return;
}
int mid = l+r>>1;
build(lson);build(rson);
pushup(rt);
}
void update(ll val,int L,int R,int l,int r,int rt){
if(L<=l && r<=R){
lazy[rt] += val;
sum[rt] += val*(r-l+1);
return;
}
pushdown(rt,r-l+1);
int mid = l+r>>1;
if(L <= mid) update(val,L,R,lson);
if(mid < R) update(val,L,R,rson);
pushup(rt);
}
ll query(int L,int R,int l,int r,int rt){
if(L<=l && r<=R){
return sum[rt];
}
pushdown(rt,r-l+1);
int mid = l+r>>1;
ll ans = 0;
if(L <= mid) ans += query(L,R,lson);
if(mid < R) ans += query(L,R,rson);
return ans;
}
int main(){
#ifdef LOCAL
freopen("c.in","r",stdin);
#endif
scanf("%d%d",&n,&q);
rep(i,1,n+1) scanf("%lld",a+i);
build(1,n,1);
rep(i,0,q){
char op[20];int a,b,c;
scanf("%s",op);
if(op[0] == 'C'){
scanf("%d%d%d",&a,&b,&c);
update(c,a,b,1,n,1);
}else{
scanf("%d%d",&a,&b);
printf("%lld\n",query(a,b,1,n,1));
}
}
return 0;
}

D - Mayor’s posters

题意

贴线段,每次贴都会覆盖掉前面的线。问贴到最后能看到多少种不同的线。

题解

线段树+离散化

覆盖线段的范围是1e8,无法建树所以需要离散化,把线段长度按照排序的顺序重新赋值。由于有$2n$个长度所以记得$maxn$要开两倍。

区间修改,单点查询。

AC代码

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
#include<cstdio>
#include<vector>
#include<algorithm>
#include<cstring>
#include<iostream>
using namespace std;
#define rep(i,a,n) for(int i=(a);i<(n);i++)
#define per(i,a,n) for(int i=(n-1);i>=(a);i--)
#define fi first
#define se second
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
typedef pair <int,int> pII;
typedef long long ll;
const int INF = 0x3f3f3f3f;
//head
const int maxn = 2e5 + 20;
int vis[maxn],lx[maxn],rx[maxn],lazy[maxn<<2],mmax[maxn<<2];
int T,n;
void pushdown(int rt){
if(lazy[rt]){
lazy[rt<<1] = lazy[rt<<1|1] = lazy[rt];
mmax[rt<<1] = mmax[rt<<1|1] = lazy[rt];
lazy[rt] = 0;
}
}
void build(int l,int r,int rt){
lazy[rt] = 0;
if(l==r){
mmax[rt] = 0;
return ;
}
int mid = l+r>>1;
build(lson); build(rson);
}
void update(int val,int L,int R,int l,int r,int rt){
if(L<=l && r<=R){
lazy[rt] = val;
mmax[rt] = val;
return ;
}
pushdown(rt);
int mid = l+r>>1;
if(L <= mid) update(val,L,R,lson);
if(mid < R) update(val,L,R,rson);
}
int query(int p,int l,int r,int rt){
if(l==r && l==p){
return mmax[rt];
}
int mid = l+r>>1;
pushdown(rt);
if(p <= mid) return query(p,lson);
if(mid < p) return query(p,rson);
}
int main(){
#ifdef LOCAL
freopen("d.in","r",stdin);
#endif
scanf("%d",&T);
while(T--){
scanf("%d",&n);
vector<int>x;
rep(i,1,n+1){
int l,r;scanf("%d%d",lx+i,rx+i);
x.push_back(lx[i]);x.push_back(rx[i]);
}
sort(x.begin(),x.end());
x.erase(unique(x.begin(),x.end()),x.end());
rep(i,1,n+1){
lx[i] = lower_bound(x.begin(),x.end(),lx[i])-x.begin()+1;
rx[i] = lower_bound(x.begin(),x.end(),rx[i])-x.begin()+1;
}
int len = x.size();
build(1,len,1);
rep(i,1,n+1){
update(i,lx[i],rx[i],1,len,1);
}
memset(vis,0,sizeof(vis));
int ans = 0;
rep(i,1,len+1){
int x = query(i,1,len,1);
if(vis[x] == 0){
ans ++;
vis[x] = 1;
}
}
printf("%d\n",ans);
}
return 0;
}

E - Just a Hook

题意

区间修改,区间查询

题解

线段树

ac代码

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
#include<cstring>
#include<stdio.h>
#include<cmath>
#include<algorithm>
#include<iostream>
using namespace std;
#define rep(i,a,n) for(int i=(a);i<(n);i++)
#define per(i,a,n) for(int i=(n-1);i>=(a);i--)
#define fi first
#define se second
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
typedef pair <int,int> pII;
typedef long long ll;
const int INF = 0x3f3f3f3f;
//head
const int maxn = 1e5 + 10;
int sum[maxn<<2],a[maxn],lazy[maxn<<2];
int n,q,T;
void pushup(int rt){
sum[rt] = sum[rt<<1]+sum[rt<<1|1];
}
void pushdown(int rt,int len){
if(lazy[rt]){
lazy[rt<<1] = lazy[rt];
lazy[rt<<1|1] = lazy[rt];
sum[rt<<1] = lazy[rt]*(len-len/2);
sum[rt<<1|1] = lazy[rt]*(len/2);
lazy[rt] = 0;
}
}
void build(int l,int r,int rt){
lazy[rt] = 0;
if(l==r){
sum[rt] = 1;
return;
}
int mid = l+r>>1;
build(lson);build(rson);
pushup(rt);
}
void update(int val,int L,int R,int l,int r,int rt){
if(L<=l && r<=R){
lazy[rt] = val;
sum[rt] = val*(r-l+1);
return;
}
pushdown(rt,r-l+1);
int mid = l+r>>1;
if(L <= mid) update(val,L,R,lson);
if(mid < R) update(val,L,R,rson);
pushup(rt);
}
int query(int L,int R,int l,int r,int rt){
if(L<=l && r<=R){
return sum[rt];
}
pushdown(rt,r-l+1);
int mid = l+r>>1;
ll ans = 0;
if(L <= mid) ans += query(L,R,lson);
if(mid < R) ans += query(L,R,rson);
return ans;
}
int main(){
#ifdef LOCAL
freopen("e.in","r",stdin);
#endif
scanf("%d",&T);
rep(test_case,1,T+1){
scanf("%d%d",&n,&q);
build(1,n,1);
rep(i,0,q){
int l,r,val; scanf("%d%d%d",&l,&r,&val);
update(val,l,r,1,n,1);
}
printf("Case %d: The total value of the hook is %d.\n",test_case,query(1,n,1,n,1));
}
return 0;
}

F.Count the Colors

题意

在一条线上区间涂颜色。

问所有颜色出现的区间块的数量。

题解

线段树+懒惰标记

需要注意的是,$n$不代表着数据的范围,8000才是数据的范围,并且由于区块间有空隙,所以离散化还有点不好做。虽然数据也只有8000。注意的是初始化的范围要覆盖到8000,不能以为到$n$就好了。


+5 $n$当坐范围

+3 误以为build函数能够初始化所有的点,但其实是要memset(vis,-1,sizeof(vis));

AC代码

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
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for(int i=(a);i<(n);i++)
#define per(i,a,n) for(int i=(n-1);i>=(a);i--)
#define fi first
#define se second
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
typedef pair <int,int> pII;
typedef long long ll;
const int INF = 0x3f3f3f3f;
//head -------------------------
const int maxn = 8e3+10;
int n;
int a[maxn<<2],lazy[maxn<<2],ans[maxn<<2],id[maxn<<2],vis[maxn<<2];
void pushdown(int rt){
if(lazy[rt]!=-1){
lazy[rt<<1] = lazy[rt<<1|1] = lazy[rt];
a[rt<<1] = a[rt<<1|1] = lazy[rt];
lazy[rt] = -1;
}
}
void build(int l,int r,int rt){
lazy[rt] = -1;
if(l==r){
a[rt] = -1;
return;
}
int mid = l+r>>1;
build(lson);build(rson);
}
void update(int val,int L,int R,int l,int r,int rt){
if(L<=l && r<=R){
a[rt] = val;
lazy[rt] = val;
return;
}
pushdown(rt);
int mid = l+r>>1;
if(L<=mid) update(val,L,R,lson);
if(mid<R) update(val,L,R,rson);
}
void query(int l,int r,int rt){
if(l==r){
vis[l] = a[rt];
return;
}
int mid = l+r>>1;
pushdown(rt);
query(lson);
query(rson);
}
int main(){
#ifdef LOCAL
freopen("1.in","r",stdin);
#endif
while(scanf("%d",&n)!=EOF){
build(1,8000,1);
memset(ans,0,sizeof(ans));
memset(vis,0,sizeof(vis));
memset(id,0,sizeof(id));
rep(i,1,n+1){
int l,r,x;scanf("%d%d%d",&l,&r,&x);
if(l>=r) continue;
update(x,l+1,r,1,8000,1);
}
query(1,8000,1);
int last = -1;
//int i = 1;
rep(i,1,maxn){
while(vis[i]==-1) i++,last=-1;
if(i>=maxn) break;
if(vis[i] != last){
last = vis[i];
ans[vis[i]]++;
}
}
rep(i,0,8000+1){
if(ans[i]==0) continue;
printf("%d %d\n",i,ans[i]);
}
puts("");
}
return 0;
}

G.Balanced Lineup

题意

求区间最大值和最小值的差

题解

可以用ST表预处理,也可以用树状数组或者是线段树,线段树的常数比较大,但他们的复杂度均是$O(nlogn)$

AC代码

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
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<cmath>
using namespace std;
#define rep(i,a,n) for(int i=(a);i<(n);i++)
#define per(i,a,n) for(int i=(n-1);i>=(a);i--)
#define fi first
#define se second
typedef pair <int,int> pII;
typedef long long ll;
const int INF = 0x3f3f3f3f;
//head
const int maxn = 5e4+20;
int mmax[maxn],mmin[maxn];
int a[maxn];
int n,q;
int lowbit(int x){
return x&-x;
}
void update(int x){
for(int i=x;i<=n;i+=lowbit(i)){
mmax[i] = a[i];
mmin[i] = a[i];
for(int j=1;j<lowbit(i);j<<=1){
mmax[i] = max(mmax[i],mmax[i-j]);
mmin[i] = min(mmin[i],mmin[i-j]);
}
}
}
int query_min(int l,int r){
int res = INF;
while(r>=l){
res = min(a[r],res);
r--;
for(;r-lowbit(r)>=l;r-=lowbit(r))
res = min(mmin[r],res);
}
return res;
}
int query_max(int l,int r){
int res = -INF;
while(r>=l){
res = max(a[r],res);
r--;
for(;r-lowbit(r)>=l;r-=lowbit(r))
res = max(mmax[r],res);
}
return res;
}
int solve(int l,int r){
return query_max(l,r)-query_min(l,r);
}
int main(){
#ifdef LOCAL
freopen("2.in","r",stdin);
#endif
scanf("%d%d",&n,&q);
rep(i,1,n+1) mmin[i]=INF,mmax[i]=-INF;
rep(i,1,n+1){
scanf("%d",a+i);
update(i);
}
while(q--){
int l,r;scanf("%d%d",&l,&r);
printf("%d\n",solve(l,r));
}
return 0;
}

H.Can you answer the queries?

题意

区间数字根号,区间查询数字和。

题解

线段树+智力门槛

因为所有数字最多根号8次就会变成1。所以我们只需要处理一下当数字为1就不用再更新区间内的数了。


acm还是靠智力和眼力啊,我想了半天都没想出来什么数学方法,原来只需要看出规律和找到最关键的突破点就ok了。

+1超时忘记开4倍数组了。。

+1 虚伪的看到了提醒要注意l,r的大小关系,妈的,这都卡,是不是人啊。

AC代码

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
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for(int i=(a);i<(n);i++)
#define per(i,a,n) for(int i=(n-1);i>=(a);i--)
#define fi first
#define se second
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
typedef pair <int,int> pII;
typedef long long ll;
const int INF = 0x3f3f3f3f;
//head
const int maxn = 1e5 + 10;
int n,q;
ll sum[maxn<<2],mmax[maxn<<2];
void pushup(int rt){
sum[rt] = sum[rt<<1] + sum[rt<<1|1];
mmax[rt] = max(mmax[rt<<1],mmax[rt<<1|1]);
}
void build(int l,int r,int rt){
if(l==r){
ll x;scanf("%lld",&x);
mmax[rt] = sum[rt] = x;
return;
}
int mid = l+r>>1;
build(lson);build(rson);
pushup(rt);
}
void update(int L,int R,int l,int r,int rt){
if(mmax[rt]==1) return;
if(l==r){
mmax[rt] = sqrt(mmax[rt]);
sum[rt] = sqrt(sum[rt]);
return;
}
int mid = l+r>>1;
if(L<=mid) update(L,R,lson);
if(mid<R) update(L,R,rson);
pushup(rt);
}
ll query(int L,int R,int l,int r,int rt){
if(L<=l && r<=R) return sum[rt];
int mid = l+r>>1;
ll ans = 0;
if(L<=mid) ans += query(L,R,lson);
if(mid<R) ans += query(L,R,rson);
return ans;
}
int main(){
#ifdef LOCAL
freopen("1.in","r",stdin);
#endif
int test_case = 1;
while(~scanf("%d",&n)){
build(1,n,1);
scanf("%d",&q);
printf("Case #%d:\n",test_case++);
while(q--){
int l,r,op;scanf("%d%d%d",&op,&l,&r);
if(l>r){
int temp = l;
l = r;
r = temp;
}
if(op==0){
update(l,r,1,n,1);
}else{
printf("%lld\n",query(l,r,1,n,1));
}
}
puts("");
}
return 0;
}

I Tunnel Warfare(前面写过了)

题意

题解

ac代码

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
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for(int i=(a);i<(n);i++)
#define per(i,a,n) for(int i=(n-1);i>=(a);i--)
#define fi first
#define se second
typedef pair <int,int> pII;
typedef long long ll;
const int INF = 0x3f3f3f3f;
//head
int n,m;
const int maxn = 5e4+20;
int bit[maxn];
int lowbit(int x){
return x&-x;
}
int query(int x){
int ans = 0;
for(int i = x;i;i-=lowbit(i)){
ans += bit[i];
}
return ans;
}
int query(int l,int r){
return query(r)-query(l-1);
}
void add(int x,int val){
for(int i=x;i<=n;i+=lowbit(i)){
bit[i] += val;
}
}
int solve_left(int l,int r){
int mid = l+r>>1;int ans = r;
while(l<=r){
mid = l+r>>1;
if(query(mid,r)==r-mid+1) r = mid-1,ans = mid;
else l = mid+1;
}
return ans;
}
int solve_right(int l,int r){
int mid,ans = l;
while(l<=r){
mid = l+r>>1;
if(query(l,mid)==mid-l+1) l=mid+1,ans = mid;
else r = mid-1;
}
return ans;
}
int vis[maxn];
int main(){
#ifdef LOCAL
freopen("2.in","r",stdin);
#endif
while(scanf("%d%d",&n,&m)!=EOF){
stack<int> st;
memset(bit,0,sizeof(bit));
memset(vis,0,sizeof(vis));
rep(i,1,n+1) add(i,1);
while(m--){
char op[20];scanf("%s",op);
if(op[0]=='D'){
int x;scanf("%d",&x);
st.push(x);
if(vis[x]) continue;
vis[x] = 1;
add(x,-1);
}else if(op[0]=='Q'){
int x;scanf("%d",&x);
if(query(x,x)==0) puts("0");
else printf("%d\n",solve_right(x,n)-solve_left(1,x)+1);
}else{
add(st.top(),1);
vis[st.top()] = 0;
st.pop();
}
}
}
return 0;
}

J.Assign the task

题意

dfs序+线段树模板题

题解

同上


+1 lazy数组没有初始化,没适应无build建树

AC代码

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
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for(int i=(a);i<(n);i++)
#define per(i,a,n) for(int i=(n-1);i>=(a);i--)
#define fi first
#define se second
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
typedef pair <int,int> pII;
typedef long long ll;
const int INF = 0x3f3f3f3f;
//head
const int maxn = 5e4+10;
int T,n,clk;
int on[maxn],in[maxn],ind[maxn],a[maxn<<2],lazy[maxn<<2];
vector<int> G[maxn];
void init(){
clk = 0;
memset(on,0,sizeof(on));
memset(in,0,sizeof(in));
memset(ind,0,sizeof(ind));
memset(a,-1,sizeof(a));
memset(lazy,-1,sizeof(lazy));
rep(i,0,n+1) G[i].clear();
}
void dfs(int u,int fa){
for(auto v:G[u]){
if(v==fa) continue;
in[v] = ++clk;
dfs(v,u);
}
on[u] = clk;
}
void pushdown(int rt){
if(lazy[rt]!=-1){
lazy[rt<<1] = lazy[rt<<1|1] = lazy[rt];
a[rt<<1] = a[rt<<1|1] = lazy[rt];
lazy[rt] = -1;
}
}
void update(int val,int L,int R,int l,int r,int rt){
if(L<=l && r<=R){
lazy[rt] = val;
a[rt] = val;
return ;
}
pushdown(rt);
int mid = l+r>>1;
if(L<=mid) update(val,L,R,lson);
if(mid<R) update(val,L,R,rson);
}
int query(int p,int l,int r,int rt){
if(l==r && p==l) return a[rt];
int mid = l+r>>1;
pushdown(rt);
if(p<=mid) return query(p,lson);
else return query(p,rson);
}
int main(){
#ifdef LOCAL
freopen("3.in","r",stdin);
#endif
scanf("%d",&T);
rep(test_case,1,T+1){
scanf("%d",&n);
init();
rep(i,0,n-1){
int u,v;scanf("%d%d",&u,&v);
G[v].push_back(u);
ind[u]++;
}
int root = 0;
rep(i,1,n+1) if(ind[i]==0){
root = i;
break;
}
in[root] = ++clk;
dfs(root,-1);
int q;scanf("%d",&q);
printf("Case #%d:\n",test_case);
while(q--){
char op[20];int x,y;
scanf("%s",op);
if(op[0]=='C'){
scanf("%d",&x);
printf("%d\n",query(in[x],1,n,1));
}else{
scanf("%d%d",&x,&y);
update(y,in[x],on[x],1,n,1);
}
}
}

return 0;
}

K.Transformation

题意

有四种操作。

  1. 将$[l,r]$区间的数字加上$val$.
  2. 将$[l,r]$区间的数字乘上$val$
  3. 将$[l,r]$区间的数字变成$val$
  4. 求区间$[l,r]$内所有数字$[1,2,3]$次方的和。

题解

线段树

对于线段树的懒惰标记和取模运算细节要求很高。

相信对于sum数组的转化大家都能够推得出来,但是关于pushdown的操作是另有玄机。

首先他的顺序很重要。得先将lazy[1]递推下去,也就是操作3把数字变成$val$,之后再进行乘法和加法的操作。对于乘法很重要的一点是你在lazy[2]标记递推的时候,其实你把子树中的加法也相当于乘了$val$,所以递推不仅要递推乘法标记,还要递推加法标记。


+3 更新Pushdown中你也要更新lazy数组的值

+1 更新的次序也有关系

+1初始化 有的要1.

+1 少写一个|1 rt[rt<<1|1]写成了rt<<1

+10000 有一个r-l+1写错了,下次写成 len 。不然很容易出错妈了个鸡

AC代码

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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for(int i=(a);i<(n);i++)
#define per(i,a,n) for(int i=(n-1);i>=(a);i--)
#define fi first
#define se second
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
template <typename T>
inline bool read (T &ret) {
char c;
int sgn;
if (c = getchar(), c == EOF) return 0; //EOF
while (c != '-' && (c < '0' || c > '9') ) {
if((c = getchar()) == EOF) return 0;
}
sgn = (c == '-') ? -1 : 1;
ret = (c == '-') ? 0 : (c - '0');
while (c = getchar(), c >= '0' && c <= '9') ret = ret * 10 + (c - '0');
ret *= sgn;
return 1;
}
typedef pair <int,int> pII;
typedef long long ll;
const int INF = 0x3f3f3f3f;
//head
const ll maxn = 1e5 + 20;
const ll mod = 1e4 + 7;
ll pp[mod+20][4],sum[4][maxn<<2];
ll lazy[maxn<<2][4];
int n,m,x,y,val;
void init(){
memset(sum,0,sizeof(sum));
memset(lazy,0,sizeof(lazy));
rep(i,0,maxn){
lazy[i][2] = 1;
}
}
void pushup(int rt){
rep(i,1,4){
sum[i][rt] = (sum[i][rt<<1] + sum[i][rt<<1|1])%mod;
}
}
void pushdown(int rt,ll len){
if(lazy[rt][3]){
ll c = lazy[rt][3]%mod;
lazy[rt<<1][1] = lazy[rt<<1|1][1] = 0;
lazy[rt<<1][2] = lazy[rt<<1|1][2] = 1;
lazy[rt<<1][3] = lazy[rt<<1|1][3] = c;
sum[1][rt<<1] = c*(len-len/2);
sum[1][rt<<1|1] = c*(len/2);
sum[2][rt<<1] = pp[c][2]*(len-len/2)%mod;
sum[2][rt<<1|1] = pp[c][2]*(len/2)%mod;
sum[3][rt<<1] = pp[c][3]*(len-len/2)%mod;
sum[3][rt<<1|1] = pp[c][3]*(len/2)%mod;
lazy[rt][3] = 0;
rep(i,1,4){
sum[i][rt<<1] %= mod;
sum[i][rt<<1|1] %= mod;
}
}
if(lazy[rt][2]!=1){
ll c = lazy[rt][2]%mod;
rep(i,1,4){
sum[i][rt<<1] *= pp[c][i];
sum[i][rt<<1|1] *= pp[c][i];
}
rep(i,1,3){
lazy[rt<<1][i] = (lazy[rt<<1][i]%mod)*c%mod;
lazy[rt<<1|1][i] = (lazy[rt<<1|1][i]%mod)*c%mod;
}
lazy[rt][2] = 1;
rep(i,1,4){
sum[i][rt<<1] %= mod;
sum[i][rt<<1|1] %= mod;
}
}
if(lazy[rt][1]){
ll c = lazy[rt][1]%mod;
lazy[rt<<1][1] += c;
lazy[rt<<1|1][1] += c;
lazy[rt<<1][1] %= mod;
lazy[rt<<1|1][1] %= mod;
sum[3][rt<<1] += 1ll*3*sum[2][rt<<1]%mod*c%mod + c*c%mod*c%mod*(len-len/2)%mod + 3*sum[1][rt<<1]%mod*c%mod*c%mod;
sum[3][rt<<1|1] += 1ll*3*sum[2][rt<<1|1]%mod*c%mod + 3*sum[1][rt<<1|1]*c%mod*c%mod + c*c%mod*c%mod*(len/2)%mod;
sum[2][rt<<1] += 1ll*2*sum[1][rt<<1]%mod*c%mod + c*c%mod*(len-len/2)%mod;
sum[2][rt<<1|1] += 1ll*2*sum[1][rt<<1|1]%mod*c%mod + c*c%mod*(len/2)%mod;
sum[1][rt<<1] += c*(len-len/2);
sum[1][rt<<1|1] += c*(len/2);
lazy[rt][1] = 0;
}
rep(i,1,4){
sum[i][rt<<1] %= mod;
sum[i][rt<<1|1] %= mod;
lazy[rt<<1|1][i] %= mod;
lazy[rt<<1][i] %= mod;
}
}
void update(int op,ll c,ll L,ll R,ll l,ll r,ll rt){
if(L<=l && r<=R){
if(op==1){
sum[3][rt] += 1ll*3*sum[2][rt]*c%mod+1ll*3*sum[1][rt]*c%mod*c%mod+c*c%mod*c%mod*(r-l+1)%mod;
sum[2][rt] += sum[1][rt]%mod*c%mod*2%mod+c*c%mod*(r-l+1)%mod;
sum[1][rt] += 1ll*(r-l+1)*c%mod;
lazy[rt][1] += c;
lazy[rt][1] %= mod;
}else if(op==2){
rep(i,1,4) sum[i][rt] *= pp[c][i];
lazy[rt][2] *= c;
lazy[rt][2] %= mod;
lazy[rt][1] *= c;
lazy[rt][1] %= mod;
}else{
rep(i,1,4) sum[i][rt] = pp[c][i]*(r-l+1)%mod;
lazy[rt][3] = c;
lazy[rt][1] = 0;lazy[rt][2] = 1;
}
rep(i,1,4) sum[i][rt] %= mod;
return;
}
pushdown(rt,r-l+1);
int mid = l+r>>1;
if(L<=mid) update(op,c,L,R,lson);
if(mid<R) update(op,c,L,R,rson);
pushup(rt);
}
ll query(int op,int L,int R,int l,int r,int rt){
if(L<=l && r<=R){
return sum[op][rt];
}
pushdown(rt,r-l+1);
int mid = l+r>>1;
ll ans = 0;
if(L<=mid) (ans += query(op,L,R,lson)%mod)%=mod;
if(mid<R) (ans += query(op,L,R,rson)%mod)%mod;
pushup(rt);
return ans%mod;
}
int main(){
#ifdef LOCAL
freopen("2.in","r",stdin);
//freopen("2.out","w",stdout);
#endif
rep(i,1,mod+1) pp[i][1] = i%mod;
rep(i,1,mod+1){
rep(j,2,4){
pp[i][j] = (ll)pp[i][j-1]*i%mod;
}
}
while(~scanf("%d%d",&n,&m)){
init();
rep(i,0,m){
int op;read(op); read(x);read(y);read(val);
if(op==4){
printf("%lld\n",query(val,x,y,1,n,1));
}else{
update(op,val,x,y,1,n,1);
}
}
}
#ifdef LOCAL
fclose(stdin);
fclose(stdout);
#endif
return 0;
}

L - Vases and Flowers

题意

做过 在我之前博客里面有。

题解

做过


+2 忘记掉可能初始不能放在A点,所以要加入一个全局变量flag,初始化maxl。

AC代码

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
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for(int i=(a);i<(n);i++)
#define per(i,a,n) for(int i=(n-1);i>=(a);i--)
#define fi first
#define se second
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
typedef pair <int,int> pII;
typedef long long ll;
const int INF = 0x3f3f3f3f;
//head
int n,now,maxl,maxr,flag;
const int maxn = 5e4+20;
int sum[maxn<<2],lazy[maxn<<2];
void pushup(int rt){
sum[rt] = sum[rt<<1] + sum[rt<<1|1];
}
void pushdown(int rt,int len){
if(lazy[rt] != -1){
lazy[rt<<1] = lazy[rt<<1|1] = lazy[rt];
sum[rt<<1] = lazy[rt]*(len-len/2);
sum[rt<<1|1] = lazy[rt]*(len/2);
lazy[rt] = -1;
}
}
void build(int l,int r,int rt){
lazy[rt] = -1;
if(l==r){
sum[rt] = 0;
return;
}
int mid = l+r>>1;
build(lson); build(rson);
pushup(rt);
}
void update1(int p,int l,int r,int rt){
if(now == 0) return;
int len = r-l+1;
if(sum[rt] == len) return;
if(l>=p && sum[rt] == 0 && len <= now){
now -= len;
sum[rt] = len;
lazy[rt] = 1;
if(flag == 0)
maxl = l,flag = 1;
maxr = max(maxr,r);
return;
}
pushdown(rt,len);
int mid = l+r>>1;
if(p<=mid) update1(p,lson);
update1(p,rson);
pushup(rt);
}
int query(int L,int R,int l,int r,int rt){
if(L<=l && r<=R){
lazy[rt] = 0;
int temp = sum[rt];
sum[rt] = 0;
return temp;
}
pushdown(rt,r-l+1);
int mid = l+r>>1;
int ans = 0;
if(L<=mid) ans += query(L,R,lson);
if(mid<R) ans += query(L,R,rson);
pushup(rt);
return ans;
}
int main(){
#ifdef LOCAL
freopen("l.in","r",stdin);
#endif
int T;scanf("%d",&T);
while(T--){
int m;scanf("%d%d",&n,&m);
build(1,n,1);
rep(i,0,m){
int op,x,y;scanf("%d%d%d",&op,&x,&y);
x++;
if(op==1){
now = y;
maxl = x;maxr = x;flag = 0;
update1(x,1,n,1);
if(now == y)
puts("Can not put any one.");
else
printf("%d %d\n",maxl-1,maxr-1);
}else{
y++;
printf("%d\n",query(x,y,1,n,1));
}
}
puts("");
}
return 0;
}

M - 约会安排

题意

对每一次查询寻找$val$长度的最前面空闲时间并占据他。

  • 如果是女神来查询,那么空闲的时间也包括基友的时间
  • 如果是基友来查询,那么只有空闲的时间可以选择
  • 如果想要学习$[l,r]$,那么$[l,r]$之间的时间都会被清空。

题解

线段树的区间合并。

这里由于要维护两个线段树,所以用结构体来构造树,不过确实使用结构体封装之后复用性高了很多。

  • 定义三个量$ll,rr,mm$分别表示从区间$[L,R]$最左边开始的最长长度和从区间最右边开始的最长长度和区间内横跨中点的最长长度。
  • 定义$maxlen$来表示区间内最长的长度来剪枝。

这样就可以更新了。

一棵树代表屌丝+女神占有的,一棵树代表女神占有的。

查询分为三种方向

  • 先查询左边开始的长度是否大于$val$,如果大于返回$L$,或者是递归左子树。
  • 再查询中间的部分长度是否大于$val$,如果大于返回$mid-rr[lc]+1$就是中点减掉从左半部分右边的长度。
  • 再查询递归右子树。

+1 区间合并中 更新父节点必须每个都更新,所以有时候你在return 之前也要更新一下。

AC代码

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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for(int i=(a);i<(n);i++)
#define per(i,a,n) for(int i=(n-1);i>=(a);i--)
#define fi first
#define se second
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
typedef pair <int,int> pII;
typedef long long ll;
const int INF = 0x3f3f3f3f;
//head ----------------------------------------
const int maxn = 1e6+20;
int T,n,m;
struct sgt{
int maxlen[maxn<<2];
int ll[maxn<<2],rr[maxn<<2],mm[maxn<<2];
int lazy[maxn<<2];
void build(int l,int r,int rt){
lazy[rt] = -1;
if(l==r){
ll[rt] = rr[rt] = 0;
mm[rt] = 1;
return;
}
int mid = l+r>>1;
build(lson); build(rson);
}
void init(){
lazy[1] = 1;
}
void pushup(int l,int r,int rt){
if(lazy[rt]>=0){
maxlen[rt] = ll[rt] = rr[rt] = mm[rt] = (lazy[rt]?(r-l+1):0);
}else{
int lc = rt<<1,rc = rt<<1|1,mid = l+r>>1;
ll[rt] = ll[lc];
if(ll[lc]==(mid-l+1)) ll[rt] += ll[rc];
mm[rt] = rr[lc] + ll[rc];
rr[rt] = rr[rc];
if(rr[rc] == r-mid) rr[rt] += rr[lc];
maxlen[rt] = max(maxlen[lc],max(maxlen[rc],mm[rt]));
}
}
void pushdown(int rt){
if(lazy[rt]>=0){
int lc=rt<<1,rc=rt<<1|1;
lazy[lc] = lazy[rc] = lazy[rt];
lazy[rt] = -1;
}
}
int query(int val,int l,int r,int rt){
pushup(l,r,rt);
//cout<<l<<' '<<r<<' '<<" ";
int lc = rt<<1,rc = rt<<1|1,mid = l+r>>1;
if(val>maxlen[rt]) return 0;
if(ll[rt] >= val) return l;
pushdown(rt);
pushup(rson);
int temp = query(val,lson);
if(temp) return temp;
if(mm[rt] >= val) return mid-rr[lc]+1;
return query(val,rson);
}
void update(int val,int L,int R,int l,int r,int rt){
if(L<=l && r<=R){
lazy[rt] = val;
pushup(l,r,rt);
return;
}
pushdown(rt);
int mid = l+r>>1;
if(L<=mid) update(val,L,R,lson);
else pushup(lson);
if(mid<R) update(val,L,R,rson);
else pushup(rson);
pushup(l,r,rt);
}
}all,ns;
char op[20];
int main(){
#ifdef LOCAL
freopen("1.in","r",stdin);
#endif
scanf("%d",&T);
rep(test_case,1,T+1){
printf("Case %d:\n",test_case);
scanf("%d%d",&n,&m);
//all.build(1,n,1); ns.build(1,n,1);
all.init(); ns.init();
while(m--){
scanf("%s",op);
if(op[0]=='D'){
int x;scanf("%d",&x);
int ans = all.query(x,1,n,1);
if(ans){
all.update(0,ans,ans+x-1,1,n,1);
printf("%d,let's fly\n",ans);
}else{
puts("fly with yourself");
}
}else if(op[0]=='N'){
int x;scanf("%d",&x);
int ans = all.query(x,1,n,1);
if(!ans) ans = ns.query(x,1,n,1);
if(ans){
all.update(0,ans,ans+x-1,1,n,1);
ns.update(0,ans,ans+x-1,1,n,1);
printf("%d,don't put my gezi\n",ans);
}else{
puts("wait for me");
}
}else{
int x,y;scanf("%d%d",&x,&y);
all.update(1,x,y,1,n,1);
ns.update(1,x,y,1,n,1);
puts("I am the hope of chinese chengxuyuan!!");
}
}
}

return 0;
}

Reference:https://www.cnblogs.com/DSChan/p/4861977.html

N.picture

题意

求多个矩形周长的并

题解

扫描线+线段树


这道题目没有离散化$X$坐标就可以做。而且例子也只有一个。。

ac代码

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
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
#define rep(i,a,n) for(int i=(a);i<(n);i++)
#define per(i,a,n) for(int i=(n-1);i>=(a);i--)
#define fi first
#define se second
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define pb push_back
typedef pair <int,int> pII;
typedef long long ll;
const int INF = 0x3f3f3f3f;
//head
int n;
const int maxn = 2e4+100;
struct node{
int lx,rx,y;
int f;
node(){}
node(int _lx,int _rx,int _y,int _f){
lx = _lx; rx = _rx; y = _y; f = _f;
}
bool operator<(const node &s) const{
return y<s.y;
}
}L[maxn<<2];
int sum[maxn<<2],lb[maxn<<2],rb[maxn<<2],seg[maxn<<2];
int flag[maxn<<2];
void pushup(int rt,int l,int r){
if(flag[rt]){
sum[rt] = r-l+1;
lb[rt] = rb[rt] = 1;
seg[rt] = 2;
}else if(l==r){
sum[rt] = lb[rt] = rb[rt] = seg[rt] = 0;
}else{
sum[rt] = sum[rt<<1] + sum[rt<<1|1];
lb[rt] = lb[rt<<1];
rb[rt] = rb[rt<<1|1];
seg[rt] = seg[rt<<1] + seg[rt<<1|1];
if(lb[rt<<1|1]&&rb[rt<<1]) seg[rt]-=2;
}
}
void update(int val,int L,int R,int l,int r,int rt){
if(L<=l && r<=R){
flag[rt] += val;
}else{
int mid = l+r>>1;
if(L<=mid) update(val,L,R,lson);
if(mid<R) update(val,L,R,rson);
}
pushup(rt,l,r);
}
int main(){
#ifdef LOCAL
freopen("1.in","r",stdin);
#endif
while(~scanf("%d",&n)){
int cnt = 0;
int maxl = INF; int maxr = -INF;
rep(i,0,n){
int x1,y1,x2,y2;
scanf("%d%d%d%d",&x1,&y1,&x2,&y2);
L[++cnt] = node(x1,x2,y1,1);
L[++cnt] = node(x1,x2,y2,-1);
maxl = min(maxl,x1);
maxr = max(maxr,x2);
}
sort(L+1,L+1+cnt);
int res = 0;
int last = 0;
rep(i,1,cnt+1){
update(L[i].f,L[i].lx,L[i].rx-1,maxl,maxr,1);
res += abs(sum[1]-last);
res += seg[1] * (L[i+1].y-L[i].y);
last = sum[1];
}
printf("%d\n",res);
}

return 0;
}