线段树
如果建了一个长度为n的线段树,给一个区间加上了1,之后通过-1归零,那么之后再在这个数组上建了一个长度为m的线段树,必须要再初始化一次!!!!
基础板子
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5+10;
int n,m,p;
int a[N],tr[N<<2], lz[N<<2];
void build(int k,int l,int r){
if(l == r) {
tr[k] = a[l];
return;
}
int mid = (l+r)>>1;
build(2*k,l,mid);
build(2*k+1,mid+1,r);
tr[k] = tr[2*k]+tr[2*k+1];
}
void pushdown(int k,int l,int r,int mid){
if(lz[k] == 0) return;
lz[2*k] += lz[k];
lz[2*k+1] += lz[k];
tr[2*k] += lz[k]*(mid-l+1);
tr[2*k+1] += lz[k]*(r-mid);
lz[k] = 0;
}
void update(int k,int ql,int qr,int l,int r,int v){
if(ql<=l && qr>=r){
tr[k] += v*(r-l+1);
lz[k] += v;
return;
}
int mid = (l+r)>>1;
pushdown(k,l,r,mid);
if(qr<=mid) update(2*k,ql,qr,l,mid,v);
else if(ql>mid) update(2*k+1,ql,qr,mid+1,r,v);
else{
update(2*k,ql,qr,l,mid,v);
update(2*k+1,ql,qr,mid+1,r,v);
}
tr[k] = tr[2*k]+tr[2*k+1];
}
int query(int k,int ql,int qr,int l,int r){
if(ql<=l && qr>=r) return tr[k];
int mid = (l+r)>>1;
pushdown(k,l,r,mid);
if(qr<=mid) return query(2*k,ql,qr,l,mid);
else if(ql>mid) return query(2*k+1,ql,qr,mid+1,r);
else return query(2*k,ql,qr,l,mid)+query(2*k+1,ql,qr,mid+1,r);
}
void init(){
for(int i = 0;i<=(n<<2);i++){
tr[i] = 0;
lz[i] = 0;//需要清0为-1
}
}
int main(){
cin >> n >> m >> p;
init() //cin以后再init
for(int i = 1;i<=n;i++){
cin >> a[i];
}
return 0;
}
常数优化
#include<bits/stdc++.h>
using namespace std;
#define ls (k<<1)
#define rs (k<<1|1)
typedef long long ll;
const int N = 2e5+10;
int n,m,p;
int a[N],tr[N<<2], lz[N<<2];
void build(int k,int l,int r){
if(l == r) {
tr[k] = a[l];
return;
}
int mid = (l+r)>>1;
build(ls,l,mid);
build(rs,mid+1,r);
tr[k] = tr[ls]+tr[rs];
}
void pushdown(int k,int l,int r,int mid){
if(lz[k] == 0) return;
lz[ls] += lz[k];
lz[rs] += lz[k];
tr[ls] += lz[k]*(mid-l+1);
tr[rs] += lz[k]*(r-mid);
lz[k] = 0;
}
void update(int k,int ql,int qr,int l,int r,int v){
if(ql<=l && qr>=r){
tr[k] += v*(r-l+1);
lz[k] += v;
return;
}
int mid = (l+r)>>1;
pushdown(k,l,r,mid);
if(qr<=mid) update(ls,ql,qr,l,mid,v);
else if(ql>mid) update(rs,ql,qr,mid+1,r,v);
else{
update(ls,ql,qr,l,mid,v);
update(rs,ql,qr,mid+1,r,v);
}
tr[k] = tr[ls]+tr[rs];
}
int query(int k,int ql,int qr,int l,int r){
if(ql<=l && qr>=r) return tr[k];
int mid = (l+r)>>1;
pushdown(k,l,r,mid);
if(qr<=mid) return query(ls,ql,qr,l,mid);
else if(ql>mid) return query(rs,ql,qr,mid+1,r);
else return query(ls,ql,qr,l,mid)+query(rs,ql,qr,mid+1,r);
}
void init(){
for(int i = 0;i<=(n<<2);i++){
tr[i] = 0;
lz[i] = 0;//需要清0为-1
}
}
int main(){
cin >> n >> m >> p;
init(); //cin以后再init
for(int i = 1;i<=n;i++){
cin >> a[i];
}
return 0;
}
扫描线
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N = 2e5+10;
struct line{
ll l,r,h;
int isout;
friend bool operator < (line &a,line &b){
return a.h<b.h;
}
};
ll tr[16*N];//矩形个数乘16
int lz[16*N];
line seg[8*N];//矩形个数乘2
ll X[8*N];
void pushup(int k,ll l,ll r) {
if (lz[k]) {//整个区间都加
tr[k] = X[r+1]-X[l];
}
else{
tr[k] = tr[2*k]+tr[2*k+1];
}
return;
}
void add(int k, ll ql, ll qr, ll l, ll r, int isout) {
if(X[r+1]<=ql || X[l]>=qr)return;//这样比较简单
if ((X[r+1] <= qr) && (X[l] >= ql)) {
lz[k] -= isout;
pushup(k,l,r);
return;
}
ll mid = (l+r)>>1;
add(2 * k, ql, qr, l, mid, isout);
add(2*k+1,ql,qr,mid+1,r,isout);
pushup(k,l,r);
return;
}
int main() {
int n;
scanf("%d",&n);
for(int i = 1;i<=n;i++){
ll x1,y1,x2,y2;
scanf("%lld%lld%lld%lld",&x1,&y1,&x2,&y2);
seg[2*i-1] = {x1,x2,y2,1};
seg[2*i] = {x1,x2,y1,-1};
X[2*i-1] = x1;
X[2*i] = x2;
}
sort(X+1,X+1+2*n);
sort(seg+1,seg+2*n+1);
int cnt = unique(X+1,X+1+2*n)-X-1;
ll ans = 0;
for(int i = 1;i<2*n;i++){
add(1,seg[i].l,seg[i].r,1,cnt-1,seg[i].isout);
ans += (seg[i+1].h-seg[i].h)*tr[1];
}
printf("%lld\n",ans);
return 0;
}
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N = 2e5+10;
int ans[N];
struct line{
ll l,r,h;
int isout;
friend bool operator < (line &a,line &b){
return a.h<b.h;
}
};
ll tr[16*N];//矩形个数乘16
int lz[16*N];
line seg[8*N];//矩形个数乘2
ll X[8*N];
void pushup(int k,ll l,ll r) {
if (lz[k]) {//整个区间都加
tr[k] = X[r+1]-X[l];
}
else{
tr[k] = tr[2*k]+tr[2*k+1];
}
return;
}
void add(int k, ll ql, ll qr, ll l, ll r, int isout) {
if(X[r+1]<=ql || X[l]>=qr)return;//这样比较简单
if ((X[r+1] <= qr) && (X[l] >= ql)) {
lz[k] -= isout;
pushup(k,l,r);
return;
}
ll mid = (l+r)>>1;
add(2 * k, ql, qr, l, mid, isout);
add(2*k+1,ql,qr,mid+1,r,isout);
pushup(k,l,r);
return;
}
struct Rec{
ll x1,y1,x2,y2;
};
vector<Rec>rec;
int main() {
int n;
ll d;
scanf("%d%lld",&n,&d);
int flag = 0;
rec.push_back({-10,0,0,0});
for(int i = 1;i<=n;i++){
ll x1,y1,x2,y2;
cin >> x1 >> y1 >> x2 >> y2;
if((x2-x1>=d) && (y2-y1>=d)) flag = 1;
x1 += (1e9)*d;
y1 += (1e9)*d;
x2 += (1e9)*d;
y2 += (1e9)*d;
if(!flag){
ll n_x1 = x1/d;
ll n_x2 = x2/d;
if(x2%d==0) n_x2-=1;
ll n_y1 = y1/d;
ll n_y2 = y2/d;
if(y2%d==0) n_y2-=1;
if((n_x1 == n_x2) && (n_y1 == n_y2)){
rec.push_back({x1-n_x1*d,y1-n_y1*d,x2-n_x2*d,y2-n_y2*d});
}
else if(n_x1 == n_x2){
rec.push_back({x1-n_x1*d,y1-n_y1*d,x2-n_x2*d,d});
rec.push_back({x1-n_x1*d,0,x2-n_x2*d,y2-n_y2*d});
}
else if(n_y1 == n_y2){
rec.push_back({x1-n_x1*d,y1-n_y1*d,d,y2-n_y2*d});
rec.push_back({0,y1-n_y1*d,x2-n_x2*d,y2-n_y2*d});
}
else{
rec.push_back({x1-n_x1*d,y1-n_y1*d,d,d});
rec.push_back({x1-n_x1*d,0,d,y2-n_y2*d});
rec.push_back({0,0,x2-n_x2*d,y2-n_y2*d});
rec.push_back({0,y1-n_y1*d,x2-n_x2*d,d});
}
}
}
if(flag){
printf("NO\n");
return 0;
}
int len = rec.size()-1;
for(int i = 1;i<=len;i++){
seg[2*i-1] = {rec[i].x1,rec[i].x2,rec[i].y2,1};
seg[2*i] = {rec[i].x1,rec[i].x2,rec[i].y1,-1};
X[2*i-1] = rec[i].x1;
X[2*i] = rec[i].x2;
}
sort(X+1,X+1+2*len);
sort(seg+1,seg+2*len+1);
int cnt = unique(X+1,X+1+2*len)-X-1;
double high = -1;
for(int i = 1;i<2*len;i++){
add(1,seg[i].l,seg[i].r,1,cnt-1,seg[i].isout);
if(tr[1]<d){
if(seg[i+1].h != seg[i].h){
high = (seg[i+1].h+seg[i].h)/2.0;
break;
}
}
}
if(high+1<1e-6) printf("NO\n");
else{
printf("YES\n");
for(Rec i : rec){
if(i.x1 == -10)continue;
if(i.y1<high && i.y2>high){
ans[i.x1] += 1;
ans[i.x2] -= 1;
}
}
if(ans[0] == 0){
cout << 0 << " " << (int)high << endl;
return 0;
}
for(int i = 1;i<d;i++){
ans[i] += ans[i-1];
if(ans[i] == 0){
cout << i << " " << (int)high << endl;
return 0;
}
}
}
return 0;
}
主席树
#include<bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
const int mod = 1e9 + 7;
typedef long long ll;
typedef pair<int, int> pii;
struct Node {
int l, r, sum;
};
Node hjt[40 * N];
vector<int> v;
int a[N], root[N], cnt = 0;
void insert(int l, int r, int pre, int& now, int p) {
hjt[++cnt] = hjt[pre];
//cout << cnt << " " << hjt[cnt].l<<" "<<hjt[cnt].r<<" " <<hjt[cnt].sum<< endl;
now = cnt;
hjt[now].sum++;
if (l == r)return;
int m = (l + r) >> 1;
if (p <= m)insert(l, m, hjt[pre].l, hjt[now].l, p);
else insert(m + 1, r, hjt[pre].r, hjt[now].r, p);
}
int query(int l, int r, int L, int R, int k) {
if (l == r)return l;
int m = (l + r) >> 1;
int tmp = hjt[hjt[R].l].sum - hjt[hjt[L].l].sum;
if (k <= tmp) return query(l, m, hjt[L].l, hjt[R].l, k);
else return query(m + 1, r, hjt[L].r, hjt[R].r, k - tmp);
}
int main() {
std::ios::sync_with_stdio(false); std::cin.tie(0);
int n, m;
cin >> n >> m;
hjt[0] = {0,0,0};
for (int i = 1; i <= n; i++) {
cin >> a[i];
v.push_back(a[i]);
}
sort(v.begin(), v.end());
v.erase(unique(v.begin(), v.end()), v.end());
for (int i = 1; i <= n; i++) {
int pos = lower_bound(v.begin(), v.end(), a[i]) - v.begin() + 1;
insert(1, v.size(), root[i - 1], root[i], pos);
}
//cout << m << endl;
while (m--) {
int l, r, k;
cin >> l >> r >> k;
cout << v[query(1, v.size(), root[l - 1], root[r], k)-1] << endl;
}
return 0;
}
找01串里任意区间内第一个出现的1
#include<bits/stdc++.h>
using namespace std;
#define ls (x<<1)
#define rs (x<<1|1)
const int N = 1e5 + 5;
const int inf = 0x3f3f3f3f;
vector<int>e[N];
int tr[2][N << 2], lz[2][N << 2];
void pushdown(int f, int x, int l, int r, int mid) {
if (lz[f][x] == -1)return;
tr[f][ls] = lz[f][x] * (mid - l + 1);
tr[f][rs] = lz[f][x] * (r - mid);
lz[f][ls] = lz[f][rs] = lz[f][x];
lz[f][x] = -1;
}
void update(int f,int x, int l, int r, int L, int R, int v) {
if (L <= l && R >= r) {
tr[f][x] = (r - l + 1) * v;
lz[f][x] = v;
return;
}
int mid = (l + r) >> 1;
pushdown(f, x, l, r, mid);
if (R <= mid)update(f, ls, l, mid, L, R, v);
else if (L > mid)update(f, rs, mid + 1, r, L, R, v);
else {
update(f, ls, l, mid, L, mid, v);
update(f, rs, mid + 1, r, mid + 1, R, v);
}
tr[f][x] = tr[f][ls] + tr[f][rs];
}
int query(int f, int x, int l, int r, int L, int R) {
if (!tr[f][x])return inf;
if (l == r)return l;
int mid = l + r >> 1;
pushdown(f, x, l, r, mid);
if (L <= l && R >= r) {
if (tr[f][ls] > 0) return query(f, ls, l, mid, l, mid);
else return query(f, rs, mid + 1, r, mid + 1, r);
}
else {
if (R <= mid)return query(f, ls, l, mid, L, R);
else if (L > mid)return query(f, rs, mid + 1, r, L, R);
else return min(query(f, ls, l, mid, L, mid), query(f, rs, mid + 1, r, mid + 1, R));
}
}
int main() {
int T;
scanf("%d", &T);
while (T--) {
int n, m, k;
scanf("%d %d %d", &n, &m, &k);
for (int i = 1; i <= n; ++i)e[i].clear();
for (int i = 1; i <= (m << 2); ++i) {
tr[0][i] = tr[1][i] = 0;
lz[0][i] = lz[1][i] = -1;//清零时用
}
for (int i = 0; i < k; ++i) {
int x, y;
scanf("%d %d", &x, &y);
e[x].push_back(y);
}
long long ans = 0;
update(0, 1, 1, m, 1, 1, 1);
for (int x = 1; x <= n; ++x) {
int l = 0;
sort(e[x].begin(), e[x].end());
for (auto& y : e[x]) {
if (y - 1 >= l + 1) {
int pos = query((x & 1) ^ 1, 1, 1, m, l + 1, y - 1);
if (pos != inf)update(x & 1, 1, 1, m, pos, y - 1, 1);
}
l = y;
}
if (l + 1 <= m) {
int pos = query((x & 1) ^ 1, 1, 1, m, l + 1, m);
if (pos != inf)update(x & 1, 1, 1, m, pos, m, 1);
}
ans += tr[x & 1][1];
update((x & 1) ^ 1, 1, 1, m, 1, m, 0);
}
printf("%lld\n", ans);
}
return 0;
}
同时实现加法和乘法
P3373 【模板】线段树 2
对于线段树的一个编号为
k
k
k的子段,设它要执行的操作是
a
x
+
b
ax+b
ax+b,则它的子节点
2
k
、
2
k
+
1
2k、2k+1
2k、2k+1也要执行这一操作,设字节点中乘法的
l
a
z
y
t
a
g
lazytag
lazytag里存的是
c
c
c,加法的
l
a
z
y
t
a
g
lazytag
lazytag里存的是
d
d
d,则执行完操作后值为
a
c
.
x
+
a
d
+
b
ac.x+ad+b
ac.x+ad+b,也就是先将
c
、
d
c、d
c、d乘上
a
a
a,再加上
b
b
b。依次递归执行。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N = 2e5+10;
ll n,m,p;
ll a[N],tr[N<<2], mul_lz[N<<2],add_lz[N<<2];
void build(ll k,ll l,ll r){
if(l == r) {
tr[k] = a[l]%p;
return;
}
ll mid = (l+r)>>1;
build(2*k,l,mid);
build(2*k+1,mid+1,r);
tr[k] = (tr[2*k]+tr[2*k+1])%p;
}
void pushdown(ll k,ll l,ll r,ll mid){
if((add_lz[k] == 0) && (mul_lz[k] == 1)) return;
add_lz[2*k] = (add_lz[2*k]*mul_lz[k]+add_lz[k])%p;
add_lz[2*k+1] = (add_lz[2*k+1]*mul_lz[k]+add_lz[k])%p;
mul_lz[2*k] = mul_lz[2*k]*mul_lz[k]%p;
mul_lz[2*k+1] = mul_lz[2*k+1]*mul_lz[k]%p;
tr[2*k] = (mul_lz[k]*tr[2*k]%p+add_lz[k]*(mid-l+1)%p)%p;
tr[2*k+1] = (mul_lz[k]*tr[2*k+1]%p+add_lz[k]*(r-mid)%p)%p;
add_lz[k] = 0;
mul_lz[k] = 1;
}
void add(ll k,ll ql,ll qr,ll l,ll r,ll v){
if(ql<=l && qr>=r){
tr[k] = (tr[k]+v*(r-l+1))%p;
add_lz[k] += v;
return;
}
ll mid = (l+r)>>1;
pushdown(k,l,r,mid);
if(qr<=mid) add(2*k,ql,qr,l,mid,v);
else if(ql>mid) add(2*k+1,ql,qr,mid+1,r,v);
else{
add(2*k,ql,qr,l,mid,v);
add(2*k+1,ql,qr,mid+1,r,v);
}
tr[k] = (tr[2*k]+tr[2*k+1])%p;
}
void mul(ll k,ll ql,ll qr,ll l,ll r,ll v){
if(ql<=l && qr>=r){
tr[k] = tr[k]*v%p;
mul_lz[k] = mul_lz[k]*v%p;
add_lz[k] = add_lz[k]*v%p;
return;
}
ll mid = (l+r)>>1;
pushdown(k,l,r,mid);
if(qr<=mid) mul(2*k,ql,qr,l,mid,v);
else if(ql>mid) mul(2*k+1,ql,qr,mid+1,r,v);
else{
mul(2*k,ql,qr,l,mid,v);
mul(2*k+1,ql,qr,mid+1,r,v);
}
tr[k] = (tr[2*k]+tr[2*k+1])%p;
}
ll query(ll k,ll ql,ll qr,ll l,ll r){
if(ql<=l && qr>=r) return tr[k]%p;
ll mid = (l+r)>>1;
pushdown(k,l,r,mid);
if(qr<=mid) return query(2*k,ql,qr,l,mid)%p;
else if(ql>mid) return query(2*k+1,ql,qr,mid+1,r)%p;
else return (query(2*k,ql,qr,l,mid)+query(2*k+1,ql,qr,mid+1,r))%p;
}
void init(){
for(ll i = 0;i<=(n<<2);i++){
tr[i] = 0;
add_lz[i] = 0;
mul_lz[i] = 1;//需要清0为-1
}
}
int main(){
ios::sync_with_stdio(false); cin.tie(0);
cin >> n >> m >> p;
init();//先cin再init
for(ll i = 1;i<=n;i++){
cin >> a[i];
}
build(1,1,n);
for(ll i = 1;i<=m;i++){
ll op,x,y,k;
cin >> op >> x >> y;
if(op == 1){
cin >> k;
mul(1,x,y,1,n,k);
}
else if(op == 2){
cin >> k;
add(1,x,y,1,n,k);
}
else{
cout << query(1,x,y,1,n) << endl;
}
}
return 0;
}
同时实现加法和求最值
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 3e6+10;
struct line{
int l,r,w;
};
line seg[N];
bool cmp(line a,line b){
return a.w<b.w;
}
int tr[N<<2],tr_min[N<<2],lz[N<<2];
void pushdown(int k,int l,int r,int mid){
if(lz[k] == 0) return;
lz[2*k] += lz[k];
lz[2*k+1] += lz[k];
tr[2*k] += lz[k]*(mid-l+1);
tr_min[2*k] +=lz[k];
tr[2*k+1] += lz[k]*(r-mid);
tr_min[2*k+1] +=lz[k];
lz[k] = 0;
}
void update(int k,int ql,int qr,int l,int r,int v){
if(ql<=l && qr>=r){
tr[k] += v*(r-l+1);
lz[k] += v;
tr_min[k] += v;
return;
}
int mid = (l+r)>>1;
pushdown(k,l,r,mid);
if(qr<=mid) update(2*k,ql,qr,l,mid,v);
else if(ql>mid) update(2*k+1,ql,qr,mid+1,r,v);
else{
update(2*k,ql,qr,l,mid,v);
update(2*k+1,ql,qr,mid+1,r,v);
}
tr[k] = tr[2*k]+tr[2*k+1];
tr_min[k] = min(tr_min[2*k],tr_min[2*k+1]);
}
int main(){
int n,m;
cin >> n >> m;
for(int i = 1;i<=n;i++){
int l,r,w;
cin >> l >> r >> w;
seg[i] = {2*l,2*r,w};
if(seg[i].l == 2) seg[i].l = 1;
}
sort(seg+1,seg+1+n,cmp);
int l = 1,r = 1,ans = 0x3f3f3f3f;
int cur_w = seg[1].w;
while(r<=n){
while(seg[r].w == cur_w){
update(1,seg[r].l,seg[r].r,1,2*m,1);
r++;
if(r>n)break;
}
while(tr_min[1]){
update(1,seg[l].l,seg[l].r,1,2*m,-1);
l++;
}
if(l != 1) ans = min(ans,seg[r-1].w-seg[l-1].w);
if(r>n)break;
cur_w = seg[r].w;
}
if(ans == 0x3f3f3f3f) cout << 0 << endl;
else cout << ans << endl;
return 0;
}
xay loves trees
在树遍历的时候同时增加一个滑动窗口,树1链的长度一定要比当前ans大。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 3e5+10;
int tr[N<<2],tr_max[N<<2],lz[N<<2];
struct node{
int l,r;
};
node son[N];
vector<int> tr1[N],tr2[N];
int stk[N],n,L,ans = 0;
void pushdown(int k,int l,int r,int mid){
if(lz[k] == 0) return;
lz[2*k] += lz[k];
lz[2*k+1] += lz[k];
tr[2*k] += lz[k]*(mid-l+1);
tr_max[2*k] += lz[k];
tr[2*k+1] += lz[k]*(r-mid);
tr_max[2*k+1] += lz[k];
lz[k] = 0;
}
void update(int k,int ql,int qr,int l,int r,int v){
if(ql<=l && qr>=r){
tr[k] += v*(r-l+1);
lz[k] += v;
tr_max[k] += v;
return;
}
int mid = (l+r)>>1;
pushdown(k,l,r,mid);
if(qr<=mid) update(2*k,ql,qr,l,mid,v);
else if(ql>mid) update(2*k+1,ql,qr,mid+1,r,v);
else{
update(2*k,ql,qr,l,mid,v);
update(2*k+1,ql,qr,mid+1,r,v);
}
tr[k] = tr[2*k]+tr[2*k+1];
tr_max[k] = max(tr_max[2*k],tr_max[2*k+1]);
}
void dfs(int u,int fa){
son[u].l = L++;
for(auto v:tr2[u]){
if(v != fa){
dfs(v,u);
}
}
son[u].r = L-1;
}
int st,en;
void dfs1(int u,int fa){
int cur = -1;
stk[++en] = u;
update(1,son[u].l,son[u].r,1,n,1);
if(tr_max[1]<=1) ans = max(ans,en-st+1);
else if(en-st+1>ans){
cur = stk[st++];
update(1,son[cur].l,son[cur].r,1,n,-1);
}
for(auto v:tr1[u]){
if(v == fa)continue;
dfs1(v,u);
}
/*回溯*/
if(cur != -1){
update(1,son[cur].l,son[cur].r,1,n,1);
stk[--st] = cur;//回溯都要回溯 !!!!!!
}
update(1,son[u].l,son[u].r,1,n,-1);
en--;//stk[en]会被覆盖所以不需要
}
void init(){
for(int i = 0;i<=(n<<2);i++){
tr[i] = 0;
lz[i] = 0;//需要清0为-1
tr_max[i] = 0;
}
for(int i = 1;i<=n;i++) stk[i] = 0;
}
int main(){
//ios::sync_with_stdio(false); cin.tie(0);
int t;
cin >> t;
while(t--){
L = 1;st = 1;en = 0;ans = 0;
cin >> n;
init();
for(int i = 1;i<=n;i++){
tr1[i].clear();
tr2[i].clear();
son[i] = {0,0};
}
for(int i = 1;i<=n-1;i++){
int u,v;
cin >> u >> v;
tr1[u].push_back(v);
tr1[v].push_back(u);
}
for(int i = 1;i<=n-1;i++){
int u,v;
cin >> u >> v;
tr2[u].push_back(v);
tr2[v].push_back(u);
}
dfs(1,0);
dfs1(1,0);
cout << ans << endl;
}
return 0;
}
实现区间加等差数列
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N = 1e6+10;
int n;
int a[N],tr[N<<3],lz_a1[N<<3],lz_d[N<<3];
vector<int>b[N];
void pushdown(int k,int l,int r,int mid){
if((lz_a1[k] == 0)&&(lz_d[k] == 0)) return;
lz_a1[2*k] += lz_a1[k];
lz_a1[2*k+1] += (lz_a1[k]+(mid+1-l)*lz_d[k]);
lz_d[2*k] += lz_d[k];
lz_d[2*k+1] += lz_d[k];
tr[2*k] += lz_a1[k]*(mid-l+1)+lz_d[k]*((mid-l+1)*(mid-l)/2);
tr[2*k+1] += (lz_a1[k]+(mid+1-l)*lz_d[k])*(r-mid)+lz_d[k]*((r-mid)*(r-mid-1)/2);
lz_a1[k] = 0;
lz_d[k] = 0;
}
void update(int k,int ql,int qr,int l, int r,int a1,int d){
if(ql<=l && qr>=r){
tr[k] += (r-l+1)*(a1+(l-ql)*d)+((r-l+1)*(r-l)/2)*d;
lz_a1[k] += (a1+(l-ql)*d);
lz_d[k] += d;
return;
}
int mid = (l+r)>>1;
pushdown(k,l,r,mid);
if(qr<=mid) update(2*k,ql,qr,l,mid,a1,d);
else if(ql>mid) update(2*k+1,ql,qr,mid+1,r,a1,d);
else{
update(2*k,ql,qr,l,mid,a1,d);
update(2*k+1,ql,qr,mid+1,r,a1,d);
}
tr[k] = tr[2*k]+tr[2*k+1];
}
ll query(int k,int ql,int qr,int l,int r){
if(ql<=l && qr>=r) return tr[k];
int mid = (l+r)>>1;
pushdown(k,l,r,mid);
if(qr<=mid) return query(2*k,ql,qr,l,mid);
else if(ql>mid) return query(2*k+1,ql,qr,mid+1,r);
else return query(2*k,ql,qr,l,mid)+query(2*k+1,ql,qr,mid+1,r);
}
int main(){
return 0;
}
每个位置最多执行有限次操作
可以暴力的对每个点进行修改,当一个点无法被修改时标记为1并且向上传递,如果有第二种操作可以一并向上传递,向下也是
Counting Stars
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5+10;
const ll mod = 998244353;
int n;
ll a[3][N],tr[3][N<<2], lz[3][N<<2];
void build(int k,int l,int r){
if(l == r) {
tr[0][k] = a[0][l];
tr[1][k] = a[1][l];
return;
}
int mid = (l+r)>>1;
build(2*k,l,mid);
build(2*k+1,mid+1,r);
tr[0][k] = (tr[0][2*k]+tr[0][2*k+1])%mod;
tr[1][k] = (tr[1][2*k]+tr[1][2*k+1])%mod;
}
void pushdown(int k){
if(lz[0][k] != 1){
lz[0][2*k] = lz[0][k]*lz[0][2*k]%mod;
lz[0][2*k+1] = lz[0][k]*lz[0][2*k+1]%mod;
tr[0][2*k] = tr[0][2*k]*lz[0][k]%mod;
tr[0][2*k+1] = tr[0][2*k+1]*lz[0][k]%mod;
lz[0][k] = 1;
}
}
void pushup(int k){
tr[0][k] = (tr[0][2*k]+tr[0][2*k+1])%mod;
tr[1][k] = (tr[1][2*k]+tr[1][2*k+1])%mod;
lz[1][k] = (lz[1][2*k]&lz[1][2*k+1]);
}
void update0(int k,int ql,int qr,int l,int r){
if(ql<=l && qr>=r){
tr[0][k] =2*tr[0][k]%mod;
lz[0][k] = 2*lz[0][k]%mod;
return;
}
int mid = (l+r)>>1;
pushdown(k);
if(qr<=mid) update0(2*k,ql,qr,l,mid);
else if(ql>mid) update0(2*k+1,ql,qr,mid+1,r);
else{
update0(2*k,ql,qr,l,mid);
update0(2*k+1,ql,qr,mid+1,r);
}
pushup(k);
}
void update1(int k,int ql,int qr,int l,int r){
if(l == r){
if(tr[1][k] == 0){
tr[0][k] = 0;
//修改了以后直接一起上传。也要pushdown
lz[1][k] = 1;
}
else{
tr[1][k] = tr[1][k]-(tr[1][k]&(-tr[1][k]));
}
return;
}
int mid = (l+r)>>1;
pushdown(k);
if(qr<=mid) {
if(!lz[1][2*k])update1(2*k,ql,qr,l,mid);
}
else if(ql>mid){
if(!lz[1][2*k+1])update1(2*k+1,ql,qr,mid+1,r);
}
else{
if(!lz[1][2*k])update1(2*k,ql,qr,l,mid);
if(!lz[1][2*k+1])update1(2*k+1,ql,qr,mid+1,r);
}
pushup(k);
}
ll query(int k,int ql,int qr,int l,int r){
//longlong的时候要返回longlong
if(ql<=l && qr>=r) return (tr[0][k]+tr[1][k])%mod;
int mid = (l+r)>>1;
pushdown(k);
if(qr<=mid) return query(2*k,ql,qr,l,mid)%mod;
else if(ql>mid) return query(2*k+1,ql,qr,mid+1,r)%mod;
else return (query(2*k,ql,qr,l,mid)+query(2*k+1,ql,qr,mid+1,r))%mod;
}
void init(){
for(int i = 0;i<=(n<<2);i++){
for(int j = 0;j<=1;j++){
tr[j][i] = 0;
lz[j][i] = 1-j;
}
}
}
int main(){
int T;
cin >> T;
while(T--){
cin >> n;
init(); //cin以后再init
for(int i = 1;i<=n;i++){
ll A;
cin >> A;
for(int j = 31;j>=0;j--){
if((1ll<<j)<=A){// 1ll !!!!!!!!!
a[0][i] = (1ll<<j);
a[1][i] = A-(1ll<<j);
break;
}
}
}
build(1,1,n);
int q;
cin >> q;
for(int i = 1;i<=q;i++){
int op,l,r;
cin >> op >> l >> r;
if(op == 1){
cout << query(1,l,r,1,n) << endl;
}
if(op == 2){
update1(1,l,r,1,n);
}
if(op == 3){
update0(1,l,r,1,n);
}
}
}
return 0;
}
染色
#include <iostream>
#include <cstdio>
#include <fstream>
#include <algorithm>
#include <cmath>
#include <deque>
#include <vector>
#include <queue>
#include <string>
#include <cstring>
#include <map>
#include <stack>
#include <set>
using namespace std;
typedef long long ll;
const int MAX = 100005;
int vis[MAX],l[MAX],r[MAX],a[MAX];
vector<int> v;
struct node {
int l, r, sum;
};
node tree[4 * MAX];
int laze_tag[4*MAX];
int build(int l, int r, int k) {
int mid = (l + r) >> 1;
if (l == r) {
tree[k].sum = 0;
tree[k].l = l;
tree[k].r = r;
return tree[k].sum;
}
else {
tree[k].l = l;
tree[k].r = r;
tree[k].sum = build(l, mid, 2 * k) + build(mid + 1, r, 2 * k + 1);
return tree[k].sum;
}
}
void pushdown(int k) {
if (laze_tag[k]) {
laze_tag[2 * k] = laze_tag[k];
laze_tag[2 * k + 1] = laze_tag[k];
laze_tag[k] = 0;
}
return;
}
void search(int l, int r, int k) {
if ((tree[k].l == tree[k].r) && (laze_tag[k] == 0)) return;
if ((tree[k].l > r) || (tree[k].r < l)) return ;
if(laze_tag[k]){
vis[laze_tag[k]] = 1;
return;
}
pushdown(k);
if (tree[2 * k].r >= l) search(l, r, 2 * k);
if (tree[2 * k + 1].l <= r)search(l, r, 2 * k + 1);
}
void add(int k, int l, int r, int x) {
if ((tree[k].r <= r) && (tree[k].l >= l)) {
laze_tag[k] = x;//一定是(l,r)完全被包住了才会有laze_tag
return;
}
pushdown(k);
if (tree[2 * k].r >= l) add(2 * k, l, r, x);
if (tree[2 * k + 1].l <= r)add(2 * k + 1, l, r, x);
return;
}
int main() {
ios::sync_with_stdio(false); cin.tie(0);
int t;
cin >> t;
while(t--){
v.clear();
int n;
cin >> n;
for(int i = 0;i<=5*n;i++){
laze_tag[i] = 0;
}
for(int i = 1;i<=n;i++){
cin >> l[i] >> r[i];
v.push_back(l[i]);
v.push_back(r[i]);
vis[i] = 0;
}
sort(v.begin(),v.end());
v.erase(unique(v.begin(),v.end()),v.end());
int kk = 1;
a[0] = 1;
for(int i = 1;i<v.size();i++){
if(v[i] == v[i-1]+1){
a[i] = ++kk;
}
else{
kk += 2;
a[i] = kk;
}
}
build(1,a[v.size()-1],1);
for(int i = 1;i<=n;i++){
l[i] = a[lower_bound(v.begin(),v.end(),l[i])-v.begin()];
r[i] = a[lower_bound(v.begin(),v.end(),r[i])-v.begin()];
add(1,l[i],r[i],i);
}
search(1,a[v.size()-1],1);
int ans = 0;
for(int i = 1;i<=n;i++){
if(vis[i]) ans++;
}
cout << ans << endl;
}
return 0;
}
权值线段树、差分线段树未完待续