能用树状数组的都能用线段树,但是树状数组写法简单
K & (-K) 是用来取最右边的1 (一个数求补,那么最右边的1不会改变)
HDU - 1166 题目链接
树状数组模板题,单点更新,区间查询
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
using namespace std;
const int N = 5e4 + 5;
int n;
int tree[N];
int lowbit(int k)
{
return k & (-k);
}
void update(int x,int k)
{
while(x <= n){
tree[x] += k;
x += lowbit(x);
}
}
int getsum(int x)
{
int ans = 0;
while(x){
ans += tree[x];
x -= lowbit(x);
}
return ans;
}
int main()
{
int t,Case = 1;
scanf("%d",&t);
while(t--){
scanf("%d",&n);
memset(tree,0,sizeof(tree));
for (int i = 1; i <= n; i++){
int x;
scanf("%d",&x);
update(i,x);
}
string s;
printf("Case %d:\n",Case++);
while(cin >> s && s != "End"){
if (s == "Add"){
int x,v;
scanf("%d %d",&x,&v);
update(x,v);
}
if (s == "Sub"){
int x,v;
scanf("%d %d",&x,&v);
update(x,-v);
}
if (s == "Query"){
int a,b;
scanf("%d %d",&a,&b);
printf("%d\n",getsum(b) - getsum(a - 1));
}
}
}
return 0;
}
HDU - 1556 题目链接
区间更新,单点查询,树状数组写法
利用差分的性质进行更新
A[] = 1 2 3 5 6 9
D[] = 1 1 1 2 1 3
D【1,i】区间的和就是 a[i] 的值
如果我们把[2,5]区间内值加上2,则变成了
A[] = 1 4 5 7 8 9
D[] = 1 3 1 2 1 1
也就是只更新了 ,D【2】+ 2,D【5】 - 2;(因为树状数组是更新 【x,n】这个区间,所以我们要更新【2,5】,那就相当于更新了【2,n】+ 2 和 【5,n】- 2)
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
int tree[N];
int n;
int lowbit(int k)
{
return k & (-k);
}
void updata(int x,int k)
{
while(x <= n){
tree[x] += k;
x += lowbit(x);
}
}
int query(int x)
{
int ans = 0;
while(x){
ans += tree[x];
x -= lowbit(x);
}
return ans;
}
int main()
{
while(scanf("%d",&n) == 1 && n){
memset(tree,0,sizeof(tree));
for (int i = 0; i < n; i++){
int a,b;
scanf("%d %d",&a,&b);
updata(a,1);
updata(b + 1,-1);
}
for (int i = 1; i < n; i++){
printf("%d ",query(i));
}
printf("%d\n",query(n));
}
return 0;
}
线段树写法
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
int tree[4 * N];
int lazy[4 * N];
void build(int L,int R,int rt)
{
if (L == R){
tree[rt] = 0;
return ;
}
int mid = (L + R) >> 1;
build(L,mid,rt << 1);
build(mid + 1,R,rt << 1 | 1);
}
void push_down(int id)
{
tree[id << 1] += lazy[id];
tree[id << 1 | 1] += lazy[id];
lazy[id << 1] += lazy[id];
lazy[id << 1 | 1] += lazy[id];
lazy[id] = 0;
}
void updata(int a,int b,int l,int r,int id)
{
if (a <= l && r <= b){
lazy[id] += 1;
tree[id] += 1;
return ;
}
int mid = (l + r) >> 1;
if (a <= mid) updata(a,b,l,mid,id << 1);
if (b > mid) updata(a,b,mid + 1,r,id << 1 | 1);
}
int query(int pos,int l,int r,int id)
{
if (l == r) return tree[id];
if (lazy[id]) push_down(id);
int mid = (l + r) >> 1;
if (pos <= mid) query(pos,l,mid,id << 1);
else query(pos,mid + 1,r,id << 1 | 1);
}
int main()
{
int n;
while(scanf("%d",&n) == 1 && n){
memset(lazy,0,sizeof(lazy));
build(1,n,1);
for (int i = 0; i < n; i++){
int a,b;
scanf("%d %d",&a,&b);
updata(a,b,1,n,1);
}
for (int i = 1; i < n; i++){
printf("%d ",query(i,1,n,1));
}
printf("%d\n",query(n,1,n,1));
}
return 0;
}
POJ - 2155 题目链接
这题就是HDU1556的升级版,就是从一维变成二维矩阵
每次改变就是变成0变1,或者1变0,所以我们记录改变的次数,然后结果 mod 2即可
更新矩阵的原理也是类似
【x1 ~ n,y1 ~ n】【x2 + 1 ~ n,y1 ~ n】【x1 ~ n,y2 + 1 ~ n】【x2 + 1~n,y2 + 1 ~ n】
图上的数字代表更新次数,偶数就相当于没更新
#include <cstdio>
#include <cstring>
using namespace std;
const int N = 1111;
int tree[N][N];
int n,q;
int lowbit(int k)
{
return k & (-k);
}
void updata(int x,int y)
{
for (int i = x; i <= n; i += lowbit(i)){
for (int j = y; j <= n; j += lowbit(j)){
tree[i][j]++;
}
}
}
int query(int x,int y)
{
int ans = 0;
for (int i = x; i > 0; i -= lowbit(i)){
for (int j = y; j > 0; j -= lowbit(j)){
ans += tree[i][j];
}
}
return ans;
}
int main()
{
int t;
scanf("%d",&t);
while(t--){
scanf("%d %d",&n,&q);
memset(tree,0,sizeof(tree));
for (int i = 0; i < q; i++){
char c;
scanf(" %c",&c);
if (c == 'C'){
int x1,y1,x3,y3;
scanf("%d %d %d %d",&x1,&y1,&x3,&y3);
updata(x1,y1);
updata(x3 + 1,y1);
updata(x1,y3 + 1);
updata(x3 + 1,y3 + 1);
}
else {
int x,y;
scanf("%d %d",&x,&y);
printf("%d\n",query(x,y) & 1);
}
}
printf("\n");
}
return 0;
}
POJ - 2299 题目链接
逆序数模板题
#include <cstdio>
#include <cstring>
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
const int N = 5e5 + 6;
typedef long long ll;
struct node{
int x,v;
bool operator < (const node &p) const{
if (v == p.v) return x < p.x;
return v < p.v;
}
}s[N];
int a[N],n,tree[N];
int lowbit(int k)
{
return k & (-k);
}
void update(int x)
{
while(x <= n){
tree[x]++;
x += lowbit(x);
}
}
int getsum(int x)
{
int ans = 0;
while(x){
ans += tree[x];
x -= lowbit(x);
}
return ans;
}
int main()
{
while(scanf("%d",&n) == 1 && n){
memset(tree,0,sizeof(tree));
for (int i = 1; i <= n; i++){
scanf("%d",&s[i].v);
s[i].x = i;
}
sort(s + 1,s + 1 + n);
for (int i = 1; i <= n; i++){
a[s[i].x] = i;
}
ll ans = 0;
for (int i = 1; i <= n; i++){
update(a[i]);
ans += i - getsum(a[i]);
}
cout << ans << endl;
}
return 0;
}
POJ - 3067 题目链接
先把左边的排好序,那么每连接一条边增加的权值就等于v(大于b的值)
v = i - sum(b)(sum[b]代表[1,b]的和)
#include <cstdio>
#include <cstring>
#include <iostream>
#include <string>
#include <algorithm>
using namespace std;
const int N = 1111;
typedef long long ll;
struct node{
int a,b;
bool operator < (const node &p) const{
if (a == p.a) return b < p.b;
return a < p.a;
}
}s[N * N];
int tree[N];
int lowbit(int k)
{
return k & (-k);
}
void update(int x)
{
while(x <= N){
tree[x]++;
x += lowbit(x);
}
}
int getsum(int x)
{
int ans = 0;
while(x){
ans += tree[x];
x -= lowbit(x);
}
return ans;
}
int main()
{
int t,Case = 1;
scanf("%d",&t);
while(t--){
int n,m,k;
scanf("%d %d %d",&n,&m,&k);
for (int i = 0; i < k; i++){
scanf("%d %d",&s[i].a,&s[i].b);
}
sort(s,s + k);
memset(tree,0,sizeof(tree));
ll ans = 0;
for (int i = 0; i < k; i++){
ans += i - getsum(s[i].b);
update(s[i].b);
}
printf("Test case %d: %I64d\n",Case++,ans);
}
return 0;
}
HDU - 1754 题目链接
线段树求区间最大值
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 5;
int tree[4 * N];
void build(int L,int R,int rt)
{
if (L == R){
scanf("%d",&tree[rt]);
return ;
}
int mid = (L + R) >> 1;
build(L,mid,rt << 1);
build(mid + 1,R,rt << 1 | 1);
tree[rt] = max(tree[rt << 1],tree[rt << 1 | 1]);
}
void updata(int pos,int x,int L,int R,int rt)
{
if (L == R){
tree[rt] = x;
return ;
}
int mid = (L + R) >> 1;
if (pos <= mid) updata(pos,x,L,mid,rt << 1);
if (pos > mid) updata(pos,x,mid + 1,R,rt << 1 | 1);
tree[rt] = max(tree[rt << 1],tree[rt << 1 | 1]);
}
int query(int a,int b,int L,int R,int rt)
{
if (a <= L && R <= b) return tree[rt];
int mid = (L + R) >> 1;
int ans = -1;
if (a <= mid) ans = max(ans,query(a,b,L,mid,rt << 1));
if (b > mid) ans = max(ans,query(a,b,mid + 1,R,rt << 1 | 1));
return ans;
}
int main()
{
int n,m;
while(scanf("%d %d",&n,&m) == 2){
build(1,n,1);
char c;
int a,b;
for (int i = 0; i < m; i++){
scanf(" %c %d %d",&c,&a,&b);
if (c == 'Q'){
printf("%d\n",query(a,b,1,n,1));
}
else {
updata(a,b,1,n,1);
}
}
}
return 0;
}
POJ - 3468 题目链接
注意 long long
线段树区间更新,区间查询
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <string>
using namespace std;
const int N = 1e5 + 5;
typedef long long ll;
ll tree[4 * N],lazy[4 * N];
void build(int l,int r,int rt)
{
if (l == r){
scanf("%I64d",&tree[rt]);
return ;
}
int mid = (l + r) >> 1;
build(l,mid,rt << 1);
build(mid + 1,r,rt << 1 | 1);
tree[rt] = tree[rt << 1] + tree[rt << 1 | 1];
}
void push_down(int id,int len)
{
//顺序不能颠倒
tree[id << 1] += lazy[id] * (len - (len >> 1));
tree[id << 1 | 1] += lazy[id] * (len >> 1);
lazy[id << 1] += lazy[id];
lazy[id << 1 | 1] += lazy[id];
lazy[id] = 0;
}
void updata(int a,int b,int x,int l,int r,int id)
{
if (a <= l && r <= b){
lazy[id] += x;
tree[id] += x * (r - l + 1);
return ;
}
if (lazy[id]) push_down(id,r - l + 1);
int mid = (l + r) >> 1;
if (a <= mid) updata(a,b,x,l,mid,id << 1);
if (b > mid) updata(a,b,x,mid + 1,r,id << 1 | 1);
tree[id] = tree[id << 1] + tree[id << 1 | 1];
}
ll query(int a,int b,int l,int r,int id)
{
if (a <= l && r <= b) return tree[id];
if (lazy[id]) push_down(id,r - l + 1);
int mid = (l + r) >> 1;
ll ans = 0;
if (a <= mid) ans += query(a,b,l,mid,id << 1);
if (b > mid) ans += query(a,b,mid + 1,r,id << 1 | 1);
tree[id] = tree[id << 1] + tree[id << 1 | 1];
return ans;
}
int main()
{
int n,m;
while(scanf("%d %d",&n,&m) == 2){
build(1,n,1);
char c;
int a,b,x;
memset(lazy,0,sizeof(lazy));
for (int i = 0; i < m; i++){
scanf(" %c",&c);
if (c == 'Q'){
scanf("%d %d",&a,&b);
printf("%I64d\n",query(a,b,1,n,1));
}
else {
scanf("%d %d %d",&a,&b,&x);
updata(a,b,x,1,n,1);
}
}
}
return 0;
}
POJ - 3264 题目链接
区间查询最值,不进行更新,可以使用
更新
RMQ:区间从2-4-8-16 ~ 开始转移
dp[i][j] 表示从下标为i开始,长度为2j的区间
dp[i][j] = min(dp [i][j - 1], dp [i + (1 << (j - 1))][j - 1])
查询:
令k = log 2 ( r − l + 1 ) \log_2({r - l + 1}) log2(r−l+1) , 则区间[l, r]的最小值RMQ[l,r] = min(dp[l][k], dp[r - (1 << k) + 1][k]);
dp[l][k]维护的是区间 [l, l + 2^k - 1] , dp[r - (1 << k) + 1][k]维护的是区间 [r - 2^k + 1, r] 。
那么只要我们保证 r - (1 << k) + 1 ≤ l + 2^k - 1就能保证RMQ[l,r] = min(dp[l][k], dp[r - (1 << k) + 1][k]);
#include <cstdio>
#include <cstring>
#include <string>
#include <cmath>
#include <algorithm>
using namespace std;
const int N = 5e4 + 5;
int mx[N][20],mi[N][20];
int a[N];
void init_max()
{
for (int j = 1; (1 << j) <= N; j++){
/// i + (1 << j) - 1 下标为i长度为(1<<j) 不能超过N
for (int i = 1; i + (1 << j) - 1 <= N; i++){
mx[i][j] = max(mx[i][j - 1],mx[i + (1 << (j - 1))][j - 1]);
}
}
}
void init_min()
{
for (int j = 1; (1 << j) <= N; j++){
for (int i = 1; i + (1 << j) - 1 <= N; i++){
mi[i][j] = min(mi[i][j - 1],mi[i + (1 << (j - 1))][j - 1]);
}
}
}
int query_max(int l,int r)
{
int k = log2(r - l + 1);
return max(mx[l][k],mx[r - (1 << k) + 1][k]);
}
int query_min(int l,int r)
{
int k = log2(r - l + 1);
return min(mi[l][k],mi[r - (1 << k) + 1][k]);
}
int main()
{
int n,m;
while (scanf("%d %d",&n,&m) == 2){
memset(mx,0,sizeof(mx));
memset(mi,0,sizeof(mi));
for (int i = 1; i <= n; i++){
scanf("%d",&a[i]);
mx[i][0] = mi[i][0] = a[i];
}
init_max();
init_min();
for (int i = 0; i < m; i++){
int x,y;
scanf("%d %d",&x,&y);
printf("%d\n",query_max(x,y) - query_min(x,y));
}
}
return 0;
}
HDU - 4027 题目链接
最开始的时候是单点更新平方根,当更新到
tree[id] == r - l + 1时,说明该区间里的数都等于1,那就不用更新了
输入的X可能会大于Y
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <string>
using namespace std;
const int N = 1e5 + 5;
typedef long long ll;
ll tree[4 * N];
void build(int l,int r,int id)
{
if (l == r){
scanf("%I64d",&tree[id]);
return ;
}
int mid = (l + r) >> 1;
build(l,mid,id << 1);
build(mid + 1,r,id << 1 | 1);
tree[id] = tree[id << 1] + tree[id << 1 | 1];
}
void updata(int a,int b,int l,int r,int id)
{
if (a <= l && r <= b && tree[id] == r - l + 1) return;
if (l == r){
tree[id] = sqrt(tree[id]);
return ;
}
int mid = (l + r) >> 1;
if (a <= mid) updata(a,b,l,mid,id << 1);
if (b > mid) updata(a,b,mid + 1,r,id << 1 | 1);
tree[id] = tree[id << 1] + tree[id << 1 | 1];
}
ll query(int a,int b,int l,int r,int id)
{
if (a <= l && r <= b) return tree[id];
int mid = (l + r) >> 1;
ll ans = 0;
if (a <= mid) ans += query(a,b,l,mid,id << 1);
if (b > mid) ans += query(a,b,mid + 1,r,id << 1 | 1);
return ans;
}
int main()
{
int n,Case = 1;
while(scanf("%d",&n) == 1){
printf("Case #%d:\n",Case++);
build(1,n,1);
int q;
scanf("%d",&q);
for (int i = 0; i < q; i++){
int op,x,y;
scanf("%d %d %d",&op,&x,&y);
if (x > y) swap(x,y);
if (op == 0){
updata(x,y,1,n,1);
}
else {
printf("%I64d\n",query(x,y,1,n,1));
}
}
printf("\n");
}
return 0;
}
POJ - 2528 题目链接
离散化加区间更新,区间查询
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
using namespace std;
const int N = 1e4 + 5;
const int INF = 0x3f3f3f3f;
typedef long long ll;
int a[N * 4],l[N],r[N];
int vis[4 * N],color[N * 16];
void push_down(int id)
{
color[id << 1] = color[id << 1 | 1] = color[id];
color[id] = 0;
}
void update(int a,int b,int x,int l,int r,int id)
{
if (a <= l && r <= b){
color[id] = x;
return ;
}
if (color[id]) push_down(id);
int mid = (l + r) >> 1;
if (a <= mid) update(a,b,x,l,mid,id << 1);
if (b > mid) update(a,b,x,mid + 1,r,id << 1 | 1);
}
int query(int a,int b,int l,int r,int id)
{
//cout << "l = " << l << " r = " << r << endl;
if (color[id]){
if (!vis[color[id]]){
vis[color[id]] = 1;
return 1;
}
}
if (l == r) return 0;
if (color[id]) push_down(id);
int mid = (l + r) >> 1;
int ans = 0;
if (a <= mid) ans += query(a,b,l,mid,id << 1);
if (b > mid) ans += query(a,b,mid + 1,r,id << 1 | 1);
return ans;
}
int main()
{
int t;
scanf("%d",&t);
while(t--){
int n;
scanf("%d",&n);
int cnt = 1;
for (int i = 0; i < n; i++){
scanf("%d %d",&l[i],&r[i]);
a[cnt++] = l[i];
a[cnt++] = r[i];
}
sort(a + 1,a + cnt);
int cnt2 = cnt;
/// 避免出现 12 24 45 离散后成 12 23 34 覆盖 23的情况
for (int i = 2; i < cnt; i++){
if (a[i] - a[i - 1] > 1){
a[cnt2++] = a[i - 1] + 1;
}
}
sort(a + 1,a + cnt2);
int num = 2;
for (int i = 2; i < cnt2; i++){
if (a[i] != a[i - 1]){
a[num++] = a[i];
}
}
memset(vis,0,sizeof(vis));
memset(color,0,sizeof(color));
for (int i = 0; i < n; i++){
int x = lower_bound(a,a + num,l[i]) - a;
int y = lower_bound(a,a + num,r[i]) - a;
// cout << "x = " << x << " y = " << y << endl;
update(x,y,i + 1,1,num - 1,1);
}
printf("%d\n",query(1,num - 1,1,num - 1,1));
}
return 0;
}
HDU - 1540 题目链接
D x 摧毁x位置
R 复原最近摧毁的位置
Q x 查询与x连接的有多少个村庄
Q (x) = min(x,n) - max(1,x)
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <stack>
using namespace std;
const int N = 5e4 + 5;
const int INF = 0x3f3f3f3f;
typedef long long ll;
int mx[N << 2],mi[N << 2],n,m;
void build(int l,int r,int id)
{
if (l == r){
mi[id] = n + 1;
mx[id] = 0;
return ;
}
int mid = (l + r) >> 1;
build(l,mid,id << 1);
build(mid + 1,r,id << 1 | 1);
mx[id] = max(mx[id << 1],mx[id << 1 | 1]);
mi[id] = min(mi[id << 1],mi[id << 1 | 1]);
}
void update_max(int pos,int x,int l,int r,int id)
{
if (l == r){
mx[id] = x;
return ;
}
int mid = (l + r) >> 1;
if (pos <= mid) update_max(pos,x,l,mid,id << 1);
if (pos > mid) update_max(pos,x,mid + 1,r,id << 1 | 1);
mx[id] = max(mx[id << 1],mx[id << 1 | 1]);
}
void update_min(int pos,int x,int l,int r,int id)
{
if (l == r){
mi[id] = x;
return ;
}
int mid = (l + r) >> 1;
if (pos <= mid) update_min(pos,x,l,mid,id << 1);
if (pos > mid) update_min(pos,x,mid + 1,r,id << 1 | 1);
mi[id] = min(mi[id << 1],mi[id << 1 | 1]);
}
int query_max(int a,int b,int l,int r,int id)
{
if (a <= l && r <= b) return mx[id];
int mid = (l + r) >> 1;
int ans = 0;
if (a <= mid) ans = max(ans,query_max(a,b,l,mid,id << 1));
if (b > mid) ans = max(ans,query_max(a,b,mid + 1,r,id << 1 | 1));
// cout << "max = " << ans << endl;
return ans;
}
int query_min(int a,int b,int l,int r,int id)
{
if (a <= l && r <= b) return mi[id];
int mid = (l + r) >> 1;
int ans = INF;
if (a <= mid) ans = min(ans,query_min(a,b,l,mid,id << 1));
if (b > mid) ans = min(ans,query_min(a,b,mid + 1,r,id << 1 | 1));
// cout << "min = " << ans << endl;
return ans;
}
int main()
{
while(scanf("%d %d",&n,&m) == 2){
char ch;
int x;
stack<int> st;
build(1,n,1);
for (int i = 0; i < m; i++){
scanf(" %c",&ch);
if (ch == 'D'){
scanf("%d",&x);
st.push(x);
update_max(x,x,1,n,1);
update_min(x,x,1,n,1);
}
else if (ch == 'R'){
x = st.top();
st.pop();
update_max(x,0,1,n,1);
update_min(x,n + 1,1,n,1);
}
else {
scanf("%d",&x);
int r = query_min(x,n,1,n,1);
int l = query_max(1,x,1,n,1);
// cout << "l = " << l << " r = " << r << endl;
if (l == r) cout << 0 << endl;
else cout << r - l - 1 << endl;
}
}
}
return 0;
}
HDU - 3974 题目链接
根据雇佣关系,生成线段树,每一个人都用一个区间表示,区间包含关系就表示雇佣关系
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <stack>
using namespace std;
const int N = 5e4 + 5;
const int INF = 0x3f3f3f3f;
typedef long long ll;
struct node{
int to,nex;
}e[N];
int head[N],vis[N],lazy[N << 2],tree[N << 2];
int cnt,num,l[N],r[N];
void add(int u,int v)
{
e[cnt].to = v;
e[cnt].nex = head[u];
head[u] = cnt++;
}
void dfs(int u)
{
l[u] = ++num;
for (int i = head[u]; i != -1; i = e[i].nex){
dfs(e[i].to);
}
r[u] = num;
}
void build(int l,int r,int id)
{
if (l == r){
tree[id] = lazy[id] = -1;
return;
}
int mid = (l + r) >> 1;
build(l,mid,id << 1);
build(mid + 1,r,id << 1 | 1);
tree[id] = lazy[id] = -1;
}
void push_down(int id)
{
lazy[id << 1] = lazy[id << 1 | 1] = lazy[id];
tree[id << 1] = tree[id << 1 | 1] = lazy[id];
lazy[id] = -1;
}
void update(int a,int b,int x,int l,int r,int id)
{
if (a <= l && r <= b){
lazy[id] = x;
tree[id] = x;
return ;
}
if (lazy[id] != -1) push_down(id);
int mid = (l + r) >> 1;
if (a <= mid) update(a,b,x,l,mid,id << 1);
if (b > mid) update(a,b,x,mid + 1,r,id << 1 | 1);
}
int query(int a,int l,int r,int id)
{
if (l == r) return tree[id];
if (lazy[id] != -1) push_down(id);
int mid = (l + r) >> 1;
int ans;
if (a <= mid) ans = query(a,l,mid,id << 1);
if (a > mid) ans = query(a,mid + 1,r,id << 1 | 1);
return ans;
}
int main()
{
int t,Case = 1;
scanf("%d",&t);
while (t--){
int n;
scanf("%d",&n);
memset(vis,0,sizeof(vis));
memset(head,-1,sizeof(head));
cnt = 0;
for (int i = 1; i < n; i++){
int u,v;
scanf("%d %d",&u,&v);
vis[u]++;
add(v,u);
}
int root;
for (int i = 1; i <= n; i++){
if (!vis[i]){
root = i;
break;
}
}
num = 0;
dfs(root);
build(1,num,1);
/*
for (int i = 0; i < n; i++){
printf("%d %d\n",l[i + 1],r[i + 1]);
}*/
int m;
scanf("%d",&m);
char ch;
int x,y;
printf("Case #%d:\n",Case++);
for (int i = 0; i < m; i++){
scanf(" %c",&ch);
if (ch == 'T'){
scanf("%d %d",&x,&y);
update(l[x],r[x],y,1,num,1);
}
else {
scanf("%d",&x);
printf("%d\n",query(l[x],1,num,1));
}
}
}
return 0;
}
HDU - 4614 题目链接
二分查找更新区间的左右端点
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <stack>
using namespace std;
const int N = 5e4 + 5;
const int INF = 0x3f3f3f3f;
typedef long long ll;
int n,m;
int lazy[N << 2],tree[N << 2];
void push_down(int id,int len)
{
lazy[id << 1] = lazy[id << 1 | 1] = lazy[id];
tree[id << 1] = lazy[id] * (len - (len >> 1));
tree[id << 1 | 1] = lazy[id] * (len >> 1);
lazy[id] = -1;
}
void update(int a,int b,int x,int l,int r,int id)
{
if (a <= l && r <= b){
lazy[id] = x;
tree[id] = x * (r - l + 1);
return ;
}
if (lazy[id] != -1) push_down(id,r - l + 1);
int mid = (l + r) >> 1;
if (a <= mid) update(a,b,x,l,mid,id << 1);
if (b > mid) update(a,b,x,mid + 1,r,id << 1 | 1);
tree[id] = tree[id << 1] + tree[id << 1 | 1];
}
int query(int a,int b,int l,int r,int id)
{
if (a <= l && r <= b) return tree[id];
if (lazy[id] != -1) push_down(id,r - l + 1);
int mid = (l + r) >> 1;
int ans = 0;
if (a <= mid) ans += query(a,b,l,mid,id << 1);
if (b > mid) ans += query(a,b,mid + 1,r,id << 1 | 1);
return ans;
}
int binary(int x,int num)
{
int l = x, r = n,ans = -1;
while (l <= r){
int mid = (l + r) >> 1;
int tem = query(x,mid,1,n,1);
if (tem + num == mid - x + 1){
ans = mid;
r = mid - 1;
}
else if (tem + num > mid - x + 1) l = mid + 1;
else r = mid - 1;
}
return ans;
}
int main()
{
int t;
scanf("%d",&t);
while (t--){
scanf("%d %d",&n,&m);
memset(tree,0,sizeof(tree));
memset(lazy,-1,sizeof(lazy));
for (int i = 0; i < m; i++){
int op,x,y;
scanf("%d %d %d",&op,&x,&y);
x++;
if (op == 1){
int st = binary(x,1);
if (st == -1) printf("Can not put any one.\n");
else {
int tem = n - x + 1 - query(x,n,1,n,1);
if (tem <= y) y = tem;
int ed = binary(x,y);
printf("%d %d\n",st - 1,ed - 1);
update(st,ed,1,1,n,1);
}
}
else{
y++;
printf("%d\n",query(x,y,1,n,1));
update(x,y,0,1,n,1);
}
}
printf("\n");
}
return 0;
}
HDU - 4578 题目链接
三重标记
定义标记的优先级 same > mult > add
如果同一层中三种标记都有,说明mult标记和add标记都是后来出现的(如果是前面已有的,那么根据优先级
same标记会清除这两个标记)
使用mult下放标记时,下放那一层如果有add标记,那么说明add标记是已经存在的,所以计算过程为
(原数 + add) * mult = (原数) * mult + add * mult (add为0,就说明没有标记,不影响结果)
mult 操作:a、b、c为原数,d为mult标记 (mult标记默认值为1)
( a d ) + ( b d ) + ( c d ) = = ( a + b + c ) ∗ d (ad) + (bd) + (cd) == ({a} + {b} + {c}) * {d} (ad)+(bd)+(cd)==(a+b+c)∗d
( a d ) 2 + ( b d ) 2 + ( c d ) 2 = = ( a 2 + b 2 + c 2 ) ∗ d 2 (ad)^2 + (bd)^2 + (cd)^2 == ({a^2} + {b^2} + {c^2}) * {d^2} (ad)2+(bd)2+(cd)2==(a2+b2+c2)∗d2
( a d ) 3 + ( b d ) 3 + ( c d ) 3 = = ( a 3 + b 3 + c 3 ) ∗ d 3 (ad)^3 + (bd)^3 + (cd)^3 == ({a^3} + {b^3} + {c^3}) * {d^3} (ad)3+(bd)3+(cd)3==(a3+b3+c3)∗d3
add操作:a、b、c为原数,d为add标记,len为区间长度(此处为3)
一次幂更新操作: ( a + d ) + ( b + d ) + ( c + d ) = = ( a + b + c ) + d ∗ l e n (a+d) + (b+d) + (c+d) == ({a} + {b} + {c}) + {d * len} (a+d)+(b+d)+(c+d)==(a+b+c)+d∗len
二次幂更新操作:
( a + d ) 2 + ( b + d ) 2 + ( c + d ) 2 = = ( a 2 + b 2 + c 2 ) + ( 2 a + 2 b + 2 c ) ∗ d + d 2 ∗ l e n (a+d)^2 + (b+d)^2 + (c+d)^2 == ({a^2} + {b^2} + {c^2}) + (2a+2b+2c) * d + {d^2 * len} (a+d)2+(b+d)2+(c+d)2==(a2+b2+c2)+(2a+2b+2c)∗d+d2∗len
( a + d ) 2 + ( b + d ) 2 + ( c + d ) 2 = = ( a 2 + b 2 + c 2 ) + 2 ∗ ( a + b + c ) ∗ d + d 2 ∗ l e n (a+d)^2 + (b+d)^2 + (c+d)^2 == ({a^2} + {b^2} + {c^2}) + 2*(a+b+c) * d + {d^2 * len} (a+d)2+(b+d)2+(c+d)2==(a2+b2+c2)+2∗(a+b+c)∗d+d2∗len
三次幂更新操作:
( a + d ) 3 + ( b + d ) 3 + ( c + d ) 3 = = ( a 3 + b 3 + c 3 ) + ( 3 a 2 + 3 b 2 + 3 c 2 ) ∗ d + ( 3 a + a b + 3 c ) ∗ d + d 3 ∗ l e n (a+d)^3 + (b+d)^3 + (c+d)^3 == ({a^3} + {b^3} + {c^3}) + (3a^2+3b^2+3c^2) * d + (3a+ab+3c) * d + {d^3 * len} (a+d)3+(b+d)3+(c+d)3==(a3+b3+c3)+(3a2+3b2+3c2)∗d+(3a+ab+3c)∗d+d3∗len
( a + d ) 3 + ( b + d ) 3 + ( c + d ) 3 = = ( a 3 + b 3 + c 3 ) + ( a 2 + b 2 + c 2 ) ∗ 3 ∗ d + ( a + b + c ) ∗ 3 ∗ d + d 3 ∗ l e n (a+d)^3 + (b+d)^3 + (c+d)^3 == ({a^3} + {b^3} + {c^3}) + (a^2+b^2+c^2) * 3* d + (a+b+c) *3* d + {d^3 * len} (a+d)3+(b+d)3+(c+d)3==(a3+b3+c3)+(a2+b2+c2)∗3∗d+(a+b+c)∗3∗d+d3∗len
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
const int mod = 10007;
typedef long long ll;
int tree[N << 2][4],add[N << 2],mult[N << 2],same[N << 2];
void push_same(int id,int x,int len)
{
same[id] = x;
add[id] = 0;
mult[id] = 1;
tree[id][1] = (len * x) % mod;
tree[id][2] = (tree[id][1] * x) % mod;
tree[id][3] = (tree[id][2] * x) % mod;
}
void push_mult(int id,int x,int len)
{
mult[id] = (mult[id] * x) % mod;
add[id] = (add[id] * x) % mod;
/// mult[id] 之前已经计算过了,这次计算x,x^2,x^3即可
int tem = x;
tree[id][1] = (tree[id][1] * tem) % mod;
tem = (tem * x) % mod;
tree[id][2] = (tree[id][2] * tem) % mod;
tem = (tem * x) % mod;
tree[id][3] = (tree[id][3] * tem) % mod;
}
void push_add(int id,int x,int len)
{
add[id] = (add[id] + x) % mod;
int sum1 = tree[id][1];
int sum2 = tree[id][2];
int tem = x % mod;
tree[id][1] += (tem * len) % mod;;
tree[id][1] %= mod;
int tem2 = (tem * x) % mod;
tree[id][2] += (2 * sum1 * tem) % mod + (tem2 * len) % mod;
tree[id][2] %= mod;
int tem3 = (tem2 * x) % mod;
tree[id][3] += (3 * sum2 * tem) % mod + (3 * sum1 * tem2) % mod + (tem3 * len) % mod;
tree[id][3] %= mod;
}
void push_down(int id,int len)
{
if (same[id]){
push_same(id << 1,same[id],len - (len >> 1));
push_same(id << 1 | 1,same[id],len >> 1);
same[id] = 0;
}
if (mult[id] != 1){
push_mult(id << 1,mult[id],len - (len >> 1));
push_mult(id << 1 | 1,mult[id],len >> 1);
mult[id] = 1;
}
if (add[id]){
push_add(id << 1,add[id],len - (len >> 1));
push_add(id << 1 | 1,add[id],len >> 1);
add[id] = 0;
}
}
void push_up(int id)
{
tree[id][1] = (tree[id << 1][1] + tree[id << 1 | 1][1]) % mod;
tree[id][2] = (tree[id << 1][2] + tree[id << 1 | 1][2]) % mod;
tree[id][3] = (tree[id << 1][3] + tree[id << 1 | 1][3]) % mod;
}
void update(int a,int b,int op,int x,int l,int r,int id)
{
if (a <= l && r <= b){
if (op == 1) push_add(id,x,r - l + 1);
else if (op == 2) push_mult(id,x,r - l + 1);
else push_same(id,x,r - l + 1);
return ;
}
push_down(id,r - l + 1);
int mid = (l + r) >> 1;
if (a <= mid) update(a,b,op,x,l,mid,id << 1);
if (b > mid) update(a,b,op,x,mid + 1,r,id << 1 | 1);
push_up(id);
}
int query(int a,int b,int x,int l,int r,int id)
{
if (a <= l && r <= b) return tree[id][x];
push_down(id,r - l + 1);
int ans = 0;
int mid = (l + r) >> 1;
if (a <= mid) ans += query(a,b,x,l,mid,id << 1);
if (b > mid) ans += query(a,b,x,mid + 1,r,id << 1 | 1);
push_up(id);
return ans % mod;
}
void build(int l,int r,int id)
{
same[id] = add[id] = 0;
mult[id] = 1;
tree[id][1] = tree[id][2] = tree[id][3] = 0;
if (l != r){
int mid = (l + r) >> 1;
build(l,mid,id << 1);
build(mid + 1,r,id << 1 | 1);
}
}
int main()
{
int n,m;
while(scanf("%d %d",&n,&m) == 2){
if (!n && !m) break;
build(1,n,1);
for (int i = 0; i < m; i++){
int op,x,y,c;
scanf("%d %d %d %d",&op,&x,&y,&c);
if (op != 4) update(x,y,op,c,1,n,1);
else printf("%d\n",query(x,y,c,1,n,1));
}
}
return 0;
}
HUD 4553 题目链接
线段树求区间并,有两种标记
区间的左连续区间等于左儿子的左连续区间,当左儿子左连续区间满了就加上右儿子的左区间
区间的右连续区间等于右儿子的右连续区间,当右儿子右连续区间满了就加上左儿子的右区间
区间最大连续区间等于 (左儿子的最大,右儿子的最大,左儿子的右区间加上右儿子的左区间)三个中的最大
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
const int mod = 10007;
typedef long long ll;
struct node{
int ls,rs,ms; /// 左边连续区间,右边连续区间,最大连续区间
}tree[N << 2][2]; /// 0屌丝,1女神
int lazy[N << 2][2];
void build(int l,int r,int id)
{
lazy[id][0] = lazy[id][1] = -1;
tree[id][0].ls = tree[id][0].rs = tree[id][0].ms = r - l + 1;
tree[id][1].ls = tree[id][1].rs = tree[id][1].ms = r - l + 1;
if (l != r){
int mid = (l + r) >> 1;
build(l,mid,id << 1);
build(mid + 1,r,id << 1 | 1);
}
}
void push_down(int id,int len,int k)
{
tree[id << 1][k].ls = tree[id << 1][k].rs = tree[id << 1][k].ms = (len - (len >> 1)) * lazy[id][k];
tree[id << 1 | 1][k].ls = tree[id << 1 | 1][k].rs = tree[id << 1 | 1][k].ms = (len >> 1) * lazy[id][k];
lazy[id << 1][k] = lazy[id << 1 | 1][k] = lazy[id][k];
lazy[id][k] = -1;
}
void push_up(int id,int len,int k)
{
tree[id][k].ls = tree[id << 1][k].ls;
tree[id][k].rs = tree[id << 1 | 1][k].rs;
if (len - (len >> 1) == tree[id << 1][k].ls) tree[id][k].ls += tree[id << 1 | 1][k].ls;
if (len >> 1 == tree[id << 1 | 1][k].rs) tree[id][k].rs += tree[id << 1][k].rs;
tree[id][k].ms = max(tree[id << 1][k].rs + tree[id << 1 | 1][k].ls,max(tree[id << 1][k].ms,tree[id << 1 | 1][k].ms));
}
void update(int a,int b,int x,int k,int l,int r,int id)
{
if (a <= l && r <= b){
lazy[id][k] = x;
tree[id][k].ls = tree[id][k].rs = tree[id][k].ms = (r - l + 1) * x;
return ;
}
if (lazy[id][k] != -1) push_down(id,r - l + 1,k);
int mid = (l + r) >> 1;
if (a <= mid) update(a,b,x,k,l,mid,id << 1);
if (b > mid) update(a,b,x,k,mid + 1,r,id << 1 | 1);
push_up(id,r - l + 1,k);
}
int query(int x,int k,int l,int r,int id)
{
if (l == r) return l;
if (lazy[id][k] != -1) push_down(id,r - l + 1,k);
int mid = (l + r) >> 1;
// cout << "id = " << id << " " << tree[id << 1][0].ms << " " << tree[id << 1][0].rs + tree[id << 1 | 1][0].ls << endl;
if (tree[id << 1][k].ms >= x) return query(x,k,l,mid,id << 1);
else if (tree[id << 1][k].rs + tree[id << 1 | 1][k].ls >= x) return mid - tree[id << 1][k].rs + 1;
else return query(x,k,mid + 1,r,id << 1 | 1);
}
int main()
{
int t,Case = 1;
scanf("%d",&t);
while(t--){
int n,m;
printf("Case %d:\n",Case++);
scanf("%d %d",&n,&m);
build(1,n,1);
char str[22];
int a,b;
for (int i = 0; i < m; i++){
scanf("%s",str);
if (str[0] == 'D'){
scanf("%d",&a);
// cout << "tree10 = " << tree[1][0].ms << endl;
// cout << "tree11 = " << tree[1][1].ms << endl;
if (tree[1][0].ms >= a){
int x = query(a,0,1,n,1);
printf("%d,let's fly\n",x);
update(x,x + a - 1,0,0,1,n,1);
}
else printf("fly with yourself\n");
}
else if (str[0] == 'N'){
scanf("%d",&a);
// cout << "tree10 = " << tree[1][0].ms << endl;
// cout << "tree11 = " << tree[1][1].ms << endl;
if (tree[1][0].ms >= a){
int x = query(a,0,1,n,1);
update(x,x + a - 1,0,0,1,n,1);
update(x,x + a - 1,0,1,1,n,1);
printf("%d,don't put my gezi\n",x);
}
else if (tree[1][1].ms >= a){
int x = query(a,1,1,n,1);
update(x,x + a - 1,0,0,1,n,1);
update(x,x + a - 1,0,1,1,n,1);
printf("%d,don't put my gezi\n",x);
}
else {
printf("wait for me\n");
}
}
else {
scanf("%d %d",&a,&b);
printf("I am the hope of chinese chengxuyuan!!\n");
update(a,b,1,0,1,n,1);
update(a,b,1,1,1,n,1);
}
}
}
return 0;
}