【数据结构杂谈】
简介:
快要省选了,现在啥也不会的菜鸡最后的挣扎
这个星期给自己的任务是搞懂网络流数据结构(我才不会说我网络流写累了)
这个星期的东西都更在这个贴里了
题目:
一: [AHOI2009] 维护序列
[AHOI2009] 维护序列
代码
#include<iostream>
#include<cstdio>
#define ll long long
#define mid ((l + r) >> 1)
ll n,cnt,t,mod,a[100005];
struct P{ll l,r,v,lazy1,lazy2;P(){lazy1 = 1;}};
inline int read(){
int x=0;
char ch=getchar();
while(!isdigit(ch))
ch=getchar();
while(isdigit(ch))
x=(x<<3)+(x<<1)+(ch^48),
ch=getchar();
return x;
}
struct Segment{
P num[(100000) << 2];
void up(ll now){num[now].v = (num[num[now].l].v + num[num[now].r].v) % mod;}
int build(ll l,ll r){
int now = ++cnt;
if(l == r){
num[now].v = a[l];
return now;
}
num[now].l = build(l,mid);
num[now].r = build(mid + 1,r);
up(now);
return now;
}
void push(ll now,ll l,ll r){
ll p = num[now].lazy1;
ll q = num[now].lazy2;
if(num[now].l){
num[num[now].l].lazy1 = num[num[now].l].lazy1 * p % mod;
num[num[now].l].lazy2 = num[num[now].l].lazy2 * p % mod;
num[num[now].l].lazy2 = (num[num[now].l].lazy2 + q) % mod;
num[num[now].l].v = (num[num[now].l].v * p + q * (mid - l + 1)) % mod;
}
if(num[now].r){
num[num[now].r].lazy1 = num[num[now].r].lazy1 * p % mod;
num[num[now].r].lazy2 = num[num[now].r].lazy2 * p % mod;
num[num[now].r].lazy2 = (num[num[now].r].lazy2 + q) % mod;
num[num[now].r].v = (num[num[now].r].v * p + q * (r - mid)) % mod;
}
num[now].lazy1 = 1;
num[now].lazy2 = 0;
return;
}
void change(ll now,ll l,ll r,ll tl,ll tr,ll p,ll q){
push(now,l,r);
if(tl <= l && r <= tr){
num[now].lazy1 = num[now].lazy1 * p % mod;
num[now].lazy2 = num[now].lazy2 * p % mod;
num[now].lazy2 = (num[now].lazy2 + q) % mod;
num[now].v = (num[now].v * p + q * (r - l + 1)) % mod;
//std::cout<<l<<" "<<r<<" "<<num[now].v<<std::endl;
return;
}
if(mid >= tl)
change(num[now].l,l,mid,tl,tr,p,q);
if(mid < tr)
change(num[now].r,mid + 1,r,tl,tr,p,q);
up(now);
return;
}
ll query(ll now,ll l,ll r,ll tl,ll tr){
//std::cout<<l<<" "<<r<<" "<<num[now].lazy1<<" "<<num[now].lazy2<<" "<<num[now].v<<std::endl;
push(now,l,r);
ll ans = 0;
if(tl <= l && r <= tr)
return num[now].v;
if(mid >= tl)
ans = (ans + query(num[now].l,l,mid,tl,tr)) % mod;
if(mid < tr)
ans = (ans + query(num[now].r,mid + 1,r,tl,tr)) % mod;
return ans;
}
}Q;
int main(){
n = read(),mod = read();
for(int i = 1;i <= n;++i)
a[i] = read();
Q.build(1,n);
t = read();
while(t -- ){
ll opt,l,r,q;
opt = read();
if(opt == 1){
l = read(),r = read(),q = read();
Q.change(1,1,n,l,r,q,0);
}
if(opt == 2){
l = read(),r = read(),q = read();
Q.change(1,1,n,l,r,1,q);
}
if(opt == 3){
l = read(),r = read();
std::cout<<Q.query(1,1,n,l,r)<<std::endl;
}
}
}
二:小白逛公园
维护区间前缀最大,后缀最大,然后合并就行
查询的时候也可以返回一个线段树类型的东西来信息储存
代码
#include<iostream>
#include<cstdio>
#define ll long long
#define mid ((l + r) >> 1)
int n,m,num[500000];
struct P{
int l,r,lmax,rmax,ans,sum;
};
struct Segment{
P t[2 * 500005];
#define l(a) t[a].l
#define r(a) t[a].r
#define lm(a) t[a].lmax
#define s(a) t[a].sum
#define rm(a) t[a].rmax
#define ans(a) t[a].ans
int cnt = 0;
void up(int now){
lm(now) = std::max(lm(l(now)),s(l(now)) + lm(r(now)));
rm(now) = std::max(rm(r(now)),s(r(now)) + rm(l(now)));
ans(now) = std::max(rm(l(now)) + lm(r(now)),std::max(ans(l(now)),ans(r(now))));
s(now) = s(l(now)) + s(r(now));
}
int build(int l,int r){
int now = ++cnt;
if(l == r){
s(now) = num[l];
lm(now) = num[l];
rm(now) = num[l];
ans(now) = num[l];
return now;
}
else{
l(now) = build(l,mid);
r(now) = build(mid + 1,r);
up(now);
}
return now;
}
void change(int l,int r,int to,int p,int now){
if(l == r){
s(now) = p;
lm(now) = p;
rm(now) = p;
ans(now) = p;
return ;
}
if(to <= mid)
change(l,mid,to,p,l(now));
else
change(mid + 1,r,to,p,r(now));
up(now);
}
P q(int l,int r,int tl,int tr,int now){
if(tl <= l && r <= tr)return t[now];
if(tl > mid)
return q(mid + 1,r,tl,tr,r(now));
if(tr <= mid)
return q(l,mid,tl,tr,l(now));
P x = q(l,mid,tl,tr,l(now)),y = q(mid + 1,r,tl,tr,r(now)),re;
re.sum = x.sum + y.sum;
re.lmax = std::max(x.sum + y.lmax,x.lmax);
re.rmax = std::max(y.sum + x.rmax,y.rmax);
re.ans = std::max(x.ans,std::max(y.ans,x.rmax + y.lmax));
return re;
}
}Q;
int main(){
scanf("%d%d",&n,&m);
for(int i = 1;i <= n;++i)
scanf("%d",&num[i]);
int q = Q.build(1,n);
for(int i = 1;i <= m;++i){
int opt,x,y;
scanf("%d%d%d",&opt,&x,&y);
if(opt == 1){
if(x > y)
std::swap(x,y);
std::cout<<Q.q(1,n,x,y,1).ans<<std::endl;
}
if(opt == 2){
Q.change(1,n,x,y,1);
}
}
}//20min写完一发A的感觉真好
三: 【模板】普通平衡树
不放链接了
我平衡树,一窍不通
要恶补
放一个\(splay\)板子吧
(\(yyb\)的板子真的好,特别优雅)
#include<iostream>
#include<cstdio>
#define ll long long
const int maxn = 500100,INF = 1e9;
int root = 0,N,tot = 0;
struct P{
int ch[2];
int ff;
int cnt;
int val;
int son;
}t[maxn];
void push_up(int u){t[u].son= t[t[u].ch[0]].son + t[t[u].ch[1]].son + t[u].cnt;}//维护子树大小
void rotate(int x){//旋转
int y = t[x].ff;
int z = t[y].ff;
int k = t[y].ch[1] == x;
t[z].ch[t[z].ch[1] == y] = x;t[x].ff = z;
t[y].ch[k] = t[x].ch[k ^ 1];t[t[x].ch[k ^ 1]].ff = y;
t[x].ch[k ^ 1] = y;t[y].ff = x;
push_up(y);push_up(x);
}
void splay(int x,int goal){
while(t[x].ff != goal){
int y = t[x].ff;
int z = t[y].ff;
if(z != goal)
(t[y].ch[0] == x) ^ (t[z].ch[0] == y) ? rotate(x) : rotate(y);
rotate(x);
}
if(goal == 0)
root = x;
}
void insert(int x){
int u = root,ff = 0;
while(u && t[u].val != x){
ff = u;
u = t[u].ch[x > t[u].val];
}
if(u)
t[u].cnt ++ ;
else{
u = ++tot;
if(ff)
t[ff].ch[x > t[ff].val] = u;
t[tot].ch[0] = 0;
t[tot].ch[1] = 0;
t[tot].ff = ff;
t[tot].val = x;
t[tot].cnt = 1;
t[tot].son = 1;
}
splay(u,0);
}
void find(int x){
int u = root;
if(!u) return;
while(t[u].ch[x > t[u].val] && x != t[u].val)
u = t[u].ch[x > t[u].val];
splay(u,0);
}
int Next(int x,int f){
find(x);
int u = root;
if((t[u].val > x && f) || (t[u].val < x & !f)) return u;
u = t[u].ch[f];
while(t[u].ch[f ^ 1]) u = t[u].ch[f ^ 1];
return u;
}
void del(int x){
int last = Next(x,0);
int next = Next(x,1);
splay(last,0);
splay(next,last);
int del = t[next].ch[0];
if(t[del].cnt > 1){
t[del].cnt -- ;
splay(del,0);
}
else
t[next].ch[0] = 0;
}
int k_th(int x){
int u = root;
if(t[u].son < x)
return false;
while(1){
int y = t[u].ch[0];
if(x > t[y].son + t[u].cnt){
x -= t[y].son + t[u].cnt;
u = t[u].ch[1];
}
else
if(t[y].son >= x)
u = y;
else
return t[u].val;
}
}
int main(){
insert(-2147483647);
insert(+2147483647);
scanf("%d",&N);
while(N -- ){
int opt;
int x;
scanf("%d%d",&opt,&x);
if(opt == 1)
insert(x);
if(opt == 2)
del(x);
if(opt == 3){
find(x);
std::cout<<t[t[root].ch[0]].son<<std::endl;
}
if(opt == 4)
std::cout<<k_th(x + 1)<<std::endl;
if(opt == 5)
std::cout<<t[Next(x,0)].val<<std::endl;
if(opt == 6)
std::cout<<t[Next(x,1)].val<<std::endl;
}
return 0;
}
四:【模板】普通平衡树(数据加强版)
折磨了我三天左右,还是不会\(splay\),奋斗了两天没有学会\(splay\)的\(Dix\)师傅,拿起了\(fhqtreap\),然后我三十分钟做完了
#include<bits/stdc++.h>
#define ll long long
#define A 2000010
inline ll read(){
ll ans = 0,f = 1;
char a = getchar();
while(a != '-' && (a < '0' || a > '9')) a = getchar();
if(a == '-') f = -1,a = getchar();
while(a <= '9' && a >= '0')
ans = (ans << 3) + (ans << 1) + (a - '0'),a = getchar();
return f * ans;
}
ll ch[A][2],val[A],cv[A],siz[A],cnt;
#define l(x) ch[x][0]
#define r(x) ch[x][1]
#define v(x) val[x]
#define c(x) cv[x]
#define s(x) siz[x]
void up(ll x){s(x) = 1 + s(l(x)) + s(r(x));}
ll randoom(){return rand() << 15 | rand();}
ll newcode(ll x){s(++cnt) = 1,v(cnt) = x,c(cnt) = randoom();return cnt;}
void split(ll now,ll k,ll &x,ll &y){
if(!now){x = y = 0;return;}
if(v(now) <= k) x = now,split(r(now),k,r(now),y);
else
y = now,split(l(now),k,x,l(now));
up(now);
}
ll merge(ll x,ll y){
if(!x || !y)return x + y;
if(c(x) < c(y)){
r(x) = merge(r(x),y);
up(x);return x;
}
else{
l(y) = merge(x,l(y));
up(y);return y;
}
}
ll root,x,y,z,cn;
void insert(ll a){
cn ++ ;
split(root,a,x,y);
root = merge(merge(x,newcode(a)),y);
}
void del(ll a){
cn -- ;
split(root,a,x,z);
split(x,a - 1,x,y);
y = merge(l(y),r(y));
root = merge(x,merge(y,z));
}
ll find(ll a){
split(root,a - 1,x,y);
ll ans = s(x) + 1;
root = merge(x,y);
return ans;
}
ll kth(ll now,ll k){
if(k <= s(l(now)))return kth(l(now),k);
else
if(k == s(l(now)) + 1)return now;
else
return kth(r(now),k - s(l(now)) - 1);
}
ll pre(ll a){
split(root,a - 1,x,y);
ll ans = v(kth(x,s(x)));
merge(x,y);
return ans;
}
ll nex(ll a){
split(root,a,x,y);
ll ans = v(kth(y,1));
merge(x,y);
return ans;
}
ll n,m;
ll last,ans;
int main(){
n = read(),m = read();
for(int i = 1;i <= n;++i){insert(read());}
for(int i = 1;i <= m;++i){
ll opt = read(),a = read() ^ last;
if(opt == 1)
insert(a);
if(opt == 2)
del(a);
if(opt == 3)
ans ^= (last = find(a));
if(opt == 4)
ans ^= (last = v(kth(root,a)));
if(opt == 5)
ans ^= (last = pre(a));
if(opt == 6)
ans ^= (last = nex(a));
}
std::cout<<ans<<std::endl;
}
五: [Ynoi2010] y-fast trie
[Ynoi2010] y-fast trie
考虑维护一些最佳匹配\(<x,y>\),\(x + y < c\),我们发现就单纯用\(multiset\)维护这样是\(O(n ^ 2)\)
我们考虑哪些是不用被记录的,假如有两个这样的匹配\(<x,y>,<y,z>,其中z < x\)那么很显然后者是不用被维护的,那么我们可以通过这个方式
排除一些不用维护的最佳匹配,那么我们发现最后这样的最佳匹配只会有\(O(n)\)个,最后在最佳匹配和\(S\)中的最大次大值的和的贡献进行比较即可
所以最后的复杂度是\(O(nlogn)\)
#include <bits/stdc++.h>
using namespace std;
int n,c,sz;
multiset<int> a,b;
multiset<int>::iterator it;
inline int best(int x,int op)
{
if(x==-1) return -1;
it=a.upper_bound(c-1-x);
if(it==a.begin()) return -1;
it--;
if(op==1 && *it==x && a.count(x)==1)
return (it==a.begin())?-1:*--it;
else
return *it;
}
inline void insert(int x)
{
sz++;
if(sz==1) { a.insert(x); return; }
int y=best(x,0),z=best(y,1),w=best(z,1);
if(y!=-1 && z<x)
{
if(z!=-1 && y==w) b.erase(b.find(y+z));
b.insert(x+y);
}
a.insert(x);
}
inline void erase(int x)
{
a.erase(a.find(x)),sz--;
if(!sz) return;
int y=best(x,0),z=best(y,1),w=best(z,1);
if(y!=-1 && z<x)
{
if(z!=-1 && y==w) b.insert(y+z);
b.erase(b.find(x+y));
}
}
inline int query()
{
it=--a.end();
if(a.count(*it)>=2) return *it*2%c;
else return (*it+*--it)%c;
}
int main()
{
scanf("%d%d",&n,&c);
int op,x,lastans=0;
while(n--)
{
scanf("%d%d",&op,&x); x^=lastans;
if(op==1) insert(x%c);
else erase(x%c);
if(sz<2) puts("EE"),lastans=0;
else printf("%d\n",lastans=max(query(),b.empty()?0:*--b.end()));
}
return 0;
}
六:小清新人渣的本愿
小清新人渣的本愿
在写上一个题的时候,我觉得如果不强制在线,那么莫队完全可以使用
于是我在\(Uoj\)问到了这题
莫队,考虑用\(bitset\)维护是否出现,加减就解决了(可以具体看代码实现)
那么乘法怎么解决呢,暴力枚举他的约数,不会出问题的\(O(\sqrt{n})\)。
代码(莫队真好写)
#include<bits/stdc++.h>
#define ll long long
ll n,m;
std::bitset<100005>f,g,ans;
ll num[100005],rt[100005];
ll cnt[100005];
struct P{
ll l,r,id,x,opt;
}q[100005];
bool operator < (P a,P b){
if(rt[a.l] == rt[b.l])
return a.r < b.r;
else
return rt[a.l] < rt[b.l];
}
void add(ll i){if(cnt[num[i]] ++ == 0)f[num[i]] = 1,g[100005 - num[i]] = 1;}
void del(ll i){if(cnt[num[i]] -- == 1)f[num[i]] = 0,g[100005 - num[i]] = 0;}
int main(){
scanf("%lld%lld",&n,&m);
ll s = sqrt(n);
for(int i = 1;i <= n;++i)
scanf("%lld",&num[i]),rt[i] = (i - 1) / s + 1;
for(int i = 1;i <= m;++i){
scanf("%lld%lld%lld%lld",&q[i].opt,&q[i].l,&q[i].r,&q[i].x);
q[i].id = i;
}
std::sort(q + 1,q + m + 1);
ll l = 0,r = 0;
for(int i = 1;i <= m;++i){
while(l < q[i].l)del(l++);
while(l > q[i].l)add(--l);
while(r < q[i].r)add(++r);
while(r > q[i].r)del(r--);
if(q[i].opt == 1){
if((f & (f << q[i].x)).any())
ans[q[i].id] = 1;
}
if(q[i].opt == 2){
if((f & (g >> (100005 - q[i].x))).any())
ans[q[i].id] = 1;
}
if(q[i].opt == 3){
for(int j = 1;j * j <= q[i].x;++j){
if(!(q[i].x % j))
if(f[j] && f[q[i].x / j]){
ans[q[i].id] = 1;
break;
}
}
}
}
for(int i = 1;i <= m;++i)
ans[i] ? puts("hana") : puts("bi");
}
七:CF438D The Child and Sequence
CF438D The Child and Sequence
三个操作
区间和
单点修改
区间膜
前两个操作都是平凡的,注意到膜这一部分,做过花神游历各国的都知道\(\sqrt{x}\)这个操作是均摊的,那么对于膜这个操作来说一样是均摊的。
考虑\(x % p\),那么知这个\(x\)至少减少了一半,所以是\(log\)级别的,我们只需要在线段树上递归时,加上一个操作就是最大值小于\(p\)时便不再做膜即可
代码
#include<bits/stdc++.h>
#define ll long long
ll n,m;
ll cnt = 0;
struct Segment{
struct P{
ll l,r,val,maxx;
}t[(100005) << 2];
#define l(x) t[x].l
#define r(x) t[x].r
#define v(x) t[x].val
#define ma(x) t[x].maxx
#define mid ((l + r) >> 1)
void up(ll now){v(now) = v(l(now)) + v(r(now)),ma(now) = std::max(ma(l(now)),ma(r(now)));}
ll build(ll l,ll r){
ll now = ++ cnt;
if(l == r){
v(now) = 0;
ma(now) = 0;
return now;
}
l(now) = build(l,mid);
r(now) = build(mid + 1,r);
up(now);
return now;
}
void change(ll now,ll l,ll r,ll p,ll x){
if(l == r){
v(now) = ma(now) = x;
return;
}
if(p <= mid)
change(l(now),l,mid,p,x);
else
change(r(now),mid + 1,r,p,x);
up(now);
return;
}
ll q_s(ll now,ll l,ll r,ll nl,ll nr){
if(nl <= l && r <= nr)
return v(now);
ll ans = 0;
if(nl <= mid)
ans += q_s(l(now),l,mid,nl,nr);
if(nr > mid)
ans += q_s(r(now),mid + 1,r,nl,nr);
return ans;
}
ll q_m(ll now,ll l,ll r,ll nl,ll nr){
if(nl <= l && r <= nr)
return ma(now);
ll ans = 0;
if(nl <= mid)
ans = std::max(ans,q_m(l(now),l,mid,nl,nr));
if(nr > mid)
ans = std::max(ans,q_m(r(now),mid + 1,r,nl,nr));
return ans;
}
void change_mod(ll now,ll l,ll r,ll nl,ll nr,ll m){
if(ma(now) < m)
return;
if(l == r){
v(now) %= m;
ma(now) %= m;
return ;
}
if(nl <= mid)
change_mod(l(now),l,mid,nl,nr,m);
if(nr > mid)
change_mod(r(now),mid + 1,r,nl,nr,m);
up(now);
}
}Q;
int main(){
scanf("%lld%lld",&n,&m);
ll s = Q.build(1,n);
for(int i = 1;i <= n;++i){
ll x;
scanf("%lld",&x);
Q.change(1,1,n,i,x);
}
for(int i = 1;i <= m;++i){
ll opt,l,r,x;
scanf("%lld",&opt);
if(opt == 1){
scanf("%lld%lld",&l,&x);
std::cout<<Q.q_s(1,1,n,l,x)<<std::endl;
}
if(opt == 2){
scanf("%lld%lld%lld",&l,&r,&x);
if(Q.q_m(1,1,n,l,r) >= x)
Q.change_mod(1,1,n,l,r,x) ;
}
if(opt == 3){
scanf("%lld%lld",&l,&x);
Q.change(1,1,n,l,x);
}
}
}