@2368860385
2018-02-03T07:17:10.000000Z
字数 21555
阅读 157
这边不包括属于NOIP难度级别的基础数据结果,包括并查集,树状数组,
inline ll read(){
ll f=1,x=0;char ch;
do{ch=getchar();if(ch=='-')f=-1;}while(ch<'0'||ch>'9');
do{x=x*10+ch-'0';ch=getchar();}while(ch>='0'&&ch<='9');
return f*x;
}
如题,已知一个数列,你需要进行下面两种操作:
#include <bits/stdc++.h>
const int N = 100005;
typedef long long ll;
using namespace std;
int a[N], n, m;
//快读read()略
ll sumv[N << 2], addv[N << 2];
#define lson (o << 1)
#define rson (o << 1 | 1)
inline void pushup( int o ) {
sumv[o] = sumv[lson] + sumv[rson];
}
inline void pushdown( int o, int l, int r ) {
if ( !addv[o] )
return;
ll tag = addv[o]; addv[o] = 0; int mid = (l + r) >> 1;
addv[lson] += tag; addv[rson] += tag;
sumv[lson] += tag * 1LL * (mid - l + 1); sumv[rson] += tag * 1LL * (r - mid);
}
inline void build( int o, int l, int r ) {
if ( l == r ) {
sumv[o] = a[l]; return;
}
int mid = (l + r) >> 1;
build( lson, l, mid ); build( rson, mid + 1, r );
pushup( o );
}
inline void optadd( int o, int l, int r, int ql, int qr, ll v ) {
if ( ql <= l && r <= qr ) {
sumv[o] += v * 1LL * (r - l + 1); addv[o] += v; return;
}
int mid = (l + r) >> 1; pushdown( o, l, r );
if ( ql <= mid )
optadd( lson, l, mid, ql, qr, v );
if ( qr > mid )
optadd( rson, mid + 1, r, ql, qr, v );
pushup( o );
}
inline ll querysum( int o, int l, int r, int ql, int qr ) {
if ( ql <= l && r <= qr )
return(sumv[o]);
pushdown( o, l, r );
int mid = (l + r) >> 1; ll ans = 0;
if ( ql <= mid )
ans += querysum( lson, l, mid, ql, qr );
if ( qr > mid )
ans += querysum( rson, mid + 1, r, ql, qr );
return(ans);
}
int main() {
n = read(); m = read();
for ( int i = 1; i <= n; i++ )
a[i] = read();
build( 1, 1, n );
while ( m-- ) {
int opt = read(), l = read(), r = read();
if ( opt == 1 ) {
ll k = read(); optadd( 1, 1, n, l, r, k );
}else printf( "%lld\n", querysum( 1, 1, n, l, r ) );
}
}
您需要写一种数据结构(可参考题目标题),来维护一些数,其中需要提供以下操作:
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cstdlib>
#define maxn 100010
using namespace std;
struct Splay {
struct Node {
int v, s;
Node *ch[2];
void maintain() {
s = ch[0]->s + ch[1]->s + 1;
}
int cmp( int k ) {
int d = k - ch[0]->s;
if ( d == 1 )
return(-1);
return(d <= 0 ? 0 : 1);
}
};
Node Pr[maxn], *root, *null; int cnt;
void init() {
cnt = 0;
null = &Pr[0]; null->s = 0; null->v = 123456; root = null;
}
Node* New( int x ) {
Pr[++cnt].v = x; Pr[cnt].ch[0] = Pr[cnt].ch[1] = null; Pr[cnt].s = 1;
return(&Pr[cnt]);
}
void rotate( Node* &i, int d ) {
Node* k = i->ch[d ^ 1];
i->ch[d ^ 1] = k->ch[d]; k->ch[d] = i;
i->maintain(); k->maintain(); i = k;
}
void splay( Node* &i, int k ) {
int d = i->cmp( k );
if ( d == 1 )
k -= i->ch[0]->s + 1;
if ( d != -1 ) {
Node *p = i->ch[d]; int d2 = p->cmp( k );
int k2 = d2 == 0 ? k : k - p->ch[0]->s - 1;
if ( d2 != -1 )
{
splay( p->ch[d2], k2 );
if ( d == d2 )
rotate( i, d ^ 1 );
else rotate( i->ch[d], d );
}
rotate( i, d ^ 1 );
}
}
void Insert( Node* &i, int x, int & d ) {
if ( i == null ) {
i = New( x ); return;
}
if ( x <= i->v )
Insert( i->ch[0], x, d );
else d += i->ch[0]->s + 1, Insert( i->ch[1], x, d );
if ( i != null )
i->maintain();
}
void insert( int x ) {
int d = 1;
Insert( root, x, d );
splay( root, d );
}
int find( int x ) {
int ans = 0; Node *p = root; bool flag = false;
while ( p != null ) {
if ( p->v == x )
flag = true;
if ( x <= p->v )
p = p->ch[0];
else ans += p->ch[0]->s + 1, p = p->ch[1];
}
if ( !flag )
return(0);
return(ans + 1);
}
int kth( Node* i, int k ) {
if ( k == i->ch[0]->s + 1 )
return(i->v);
if ( k <= i->ch[0]->s )
return(kth( i->ch[0], k ) );
else return(kth( i->ch[1], k - i->ch[0]->s - 1 ) );
}
int pre( int x ) {
Node* p = root; int ans;
while ( p != null ) {
if ( p->v < x )
ans = p->v;
if ( x <= p->v )
p = p->ch[0];
else p = p->ch[1];
}
return(ans);
}
int nex( int x ) {
Node* p = root; int ans;
while ( p != null ) {
if ( p->v > x )
ans = p->v;
if ( x >= p->v )
p = p->ch[1];
else p = p->ch[0];
}
return(ans);
}
Node* merge( Node* left, Node* right ) {
if ( left == null )
return(right);
if ( right == null )
return(left);
splay( left, left->s );
left->ch[1] = right;
left->maintain();
return(left);
}
void Delete( int x ) {
int d = find( x );
if ( !d )
return;
splay( root, d );
root = merge( root->ch[0], root->ch[1] );
}
} splay;
int main() {
int n;
scanf( "%d", &n );
splay.init();
while ( n-- ) {
int opt, x;
scanf( "%d%d", &opt, &x );
if ( opt == 1 ) splay.insert( x );
if ( opt == 2 ) splay.Delete( x );
if ( opt == 3 ) printf( "%d\n", splay.find( x ) );
if ( opt == 4 ) int k = splay.kth( splay.root, x ); printf( "%d\n", k );
if ( opt == 5 ) printf( "%d\n", splay.pre( x ) );
if ( opt == 6 ) printf( "%d\n", splay.nex( x ) );
}
return(0);
}
题面同上
#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
#define N 100005
#define inf 1000000007
using namespace std;
int n;
//快读read()略
struct Treap {
int l[N], r[N], val[N], rnd[N], size[N], w[N], sz, ans, rt;
inline void pushup( int x ) {
size[x] = size[l[x]] + size[r[x]] + w[x];
}
void rturn( int &k ) {
int t = l[k]; l[k] = r[t]; r[t] = k; size[t] = size[k]; pushup( k ); k = t;
}
void lturn( int &k ) {
int t = r[k]; r[k] = l[t]; l[t] = k; size[t] = size[k]; pushup( k ); k = t;
}
void ins( int &k, int x ) {
if ( k == 0 ) {
sz++; k = sz; size[k] = 1; w[k] = 1; val[k] = x; rnd[k] = rand(); return;
}
size[k]++;
if ( val[k] == x )
w[k]++;
else if ( val[k] < x ) {
ins( r[k], x );
if ( rnd[r[k]] < rnd[k] )
lturn( k );
}else{
ins( l[k], x );
if ( rnd[l[k]] < rnd[k] )
rturn( k );
}
}
void del( int &k, int x ) {
if ( !k )
return;
if ( val[k] == x ) {
if ( w[k] > 1 ) {
w[k]--; size[k]--; return;
}
if ( l[k] * r[k] == 0 )
k = l[k] + r[k];
else if ( rnd[l[k]] < rnd[r[k]] )
rturn( k ), del( k, x );
else lturn( k ), del( k, x );
}else if ( val[k] < x ) {
size[k]--; del( r[k], x );
}else {
size[k]--; del( l[k], x );
}
}
int queryrank( int k, int x ) {
if ( !k )
return(0);
if ( val[k] == x )
return(size[l[k]] + 1);
else if ( x > val[k] )
return(size[l[k]] + w[k] + queryrank( r[k], x ) );
else return(queryrank( l[k], x ) );
}
int querynum( int k, int x ) {
if ( k == 0 )
return(0);
if ( x <= size[l[k]] )
return(querynum( l[k], x ) );
else if ( x > size[l[k]] + w[k] )
return(querynum( r[k], x - size[l[k]] - w[k] ) );
else return(val[k]);
}
void querypre( int k, int x ) {
if ( k == 0 )
return;
if ( val[k] < x ) {
ans = k; querypre( r[k], x );
}else querypre( l[k], x );
}
void querysub( int k, int x ) {
if ( k == 0 )
return;
if ( val[k] > x ) {
ans = k; querysub( l[k], x );
}else querysub( r[k], x );
}
} T;
int main() {
n = read(); int opt, x;
for ( int i = 1; i <= n; i++ ) {
opt = read(), x = read();
switch ( opt ) {
case 1: T.ins( T.rt, x ); break;
case 2: T.del( T.rt, x ); break;
case 3: printf( "%d\n", T.queryrank( T.rt, x ) ); break;
case 4: printf( "%d\n", T.querynum( T.rt, x ) ); break;
case 5: T.ans = 0; T.querypre( T.rt, x ); printf( "%d\n", T.val[T.ans] ); break;
case 6: T.ans = 0; T.querysub( T.rt, x ); printf( "%d\n", T.val[T.ans] ); break;
}
}
return(0);
}
题面同上
#include < bits/stdc ++.h>
#define N 100010
#define mp make_pair
using namespace std;
typedef pair < int, int> par;
int n, x, rt;
struct Treap_Without_rotate{
int ls[N], rs[N], rnd[N], val[N], size[N], cnt;
inline void pushup(int x){size[x] = size[ls[x]] + size[rs[x]] + 1; }
par split(int k, int x){
if(!x)return mp(0, k);
int l = ls[k], r = rs[k];
if(x == size[l]){
ls[k] = 0; pushup(k);
return mp(l, k);
}
if(x == size[l] + 1){
rs[k] = 0; pushup(k);
return mp(k, r);
}
if(x < size[l]){
par tmp = split(l, x);
ls[k] = tmp.second; pushup(k);
return mp(tmp.first, k);
}
par tmp = split(r, x - size[l] - 1);
rs[k] = tmp.first; pushup(k);
return mp(k, tmp.second);
}
int merge(int x, int y){
if(x == 0 || y == 0)
return x + y;
if(rnd[x] < rnd[y]){
rs[x] = merge(rs[x], y); pushup(x);
return x;
}
else{
ls[y] = merge(x, ls[y]); pushup(y);
return y;
}
}
int queryrank(int x, int k){
int ans = 0, tmp = (int)1e9;
while(k){
if(x == val[k])tmp = min(tmp, ans + size[ls[k]] + 1);
if(x>val[k])ans + = size[ls[k]] + 1, k = rs[k];
else k = ls[k];
}
return tmp == (int)1e9?ans:tmp;
}
int find(int x, int k){
for(; ; ){
if(size[ls[k]] == x - 1)return val[k];
if(size[ls[k]]>x - 1)k = ls[k];
else x = x - size[ls[k]] - 1, k = rs[k];
}
}
int querypre(int x, int k){
int ans = -(int)1e9;
while(k){
if(val[k] < x)ans = max(ans, val[k]), k = rs[k];
else k = ls[k];
}
return ans;
}
int querysub(int x, int k){
int ans = (int)1e9;
while(k){
if(val[k]>x)ans = min(ans, val[k]), k = ls[k];
else k = rs[k];
}
return ans;
}
void ins(int x){
int k = queryrank(x, rt); par tmp = split(rt, k);
val[ ++cnt] = x; rnd[cnt] = rand(); size[cnt] = 1;
rt = merge(tmp.first, cnt); rt = merge(rt, tmp.second);
}
void del(int x){
int k = queryrank(x, rt); par t1 = split(rt, k), t2 = split(t1.first, k - 1);
rt = merge(t2.first, t1.second);
}
} T;
int main(){
n = read(); srand(2333333);
for(int i = 1; i < = n; i ++){
int opt = read(), x = read();
if(opt == 1)T.ins(x);
if(opt == 2)T.del(x);
if(opt == 3)printf("%d\n", T.queryrank(x, rt));
if(opt == 4)printf("%d\n", T.find(x, rt));
if(opt == 5)printf("%d\n", T.querypre(x, rt));
if(opt == 6)printf("%d\n", T.querysub(x, rt));
}
return 0;
}
如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作:
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn = 300000;
struct tree{int l, r, v, lazy; }node[2*maxn];
int first[maxn], last[maxn], nxt[maxn], a[maxn], w[maxn], tid[maxn],
e[maxn], top[maxn], rank[maxn], size[maxn], r[maxn], tt[maxn], father[maxn],
n, m, k, mod, x, y, g, i, s, tot, z;
void add(int x, int y){
a[++k] = y; tt[x]++;
if(first[x] == 0)
first[x] = k;
else
nxt[last[x]] = k;
last[x] = k;
}
void build(int u, int l, int r){
int mid = (l + r) / 2; node[u].l = l; node[u].r = r;
if(l == r)return;
build(u*2, l, mid);
build(u*2+1, mid+1, r);
}
void down(int u){
if(node[u].lazy == 0)return;
node[u].v += node[u].lazy*(node[u].r-node[u].l+1)%mod;
node[u*2].lazy += node[u].lazy; node[u*2+1].lazy += node[u].lazy;
node[u].lazy = 0;
}
void change(int u, int l, int r, int cont){
if(node[u].l > r||node[u].r<l)return;
if(node[u].l >= l&&node[u].r< = r){
node[u].lazy += cont; down(u);
return;
}
change(u*2, l, r, cont);
change(u*2+1, l, r, cont);
down(u*2); down(u*2+1);
node[u].v = (node[u*2].v+node[u*2+1].v)%mod;
}
int query(int u, int l, int r){
if(node[u].l > r||node[u].r<l)return 0;
if(node[u].l >= l&&node[u].r< = r)return (node[u].v)%mod;
down(u*2); down(u*2+1);
return(query(u*2, l, r)+query(u*2+1, l, r))%mod;
}
void dfs(int u, int fa){
int i = 0; size[u] = 1; r[u] = r[fa]+1;
father[u] = fa;
for(i = first[u]; i; i = nxt[i])
if(a[i]! = fa)
{
dfs(a[i], u);
size[u] += size[a[i]];
}
}
void dfs2(int u, int head){
int i, mson = 0;
top[u] = head; tid[u] = ++tot; rank[tid[u]] = tot;
change(1, tot, tot, w[u]);
if(tt[u] == 1&&u! = s){
e[u] = u;
return;
}
for(i = first[u]; i>0; i = nxt[i])
if(size[a[i]]<size[u]&&size[a[i]]>size[mson])
mson = a[i];
dfs2(mson, head);
e[u] = e[mson];
for(i = first[u]; i>0; i = nxt[i])
if(size[a[i]]<size[u]&&a[i]! = mson){
dfs2(a[i], a[i]); e[u] = e[a[i]];
}
}
void schange(int x, int y, int cont){
while(top[x]! = top[y]) {
if(r[top[x]]<r[top[y]])swap(x, y);
change(1, tid[top[x]], tid[x], cont);
x = father[top[x]];
}
if(tid[x]>tid[y])swap(x, y);
change(1, tid[x], tid[y], cont);
}
int squery(int x, int y){
int ans = 0;
while(top[x]! = top[y]){
if(r[top[x]]<r[top[y]])swap(x, y);
ans += query(1, tid[top[x]], tid[x]);
ans %= mod;
x = father[top[x]];
}
if(tid[x]>tid[y])swap(x, y);
ans += query(1, tid[x], tid[y]);
ans %= mod;
return ans;
}
int main(){
scanf("%d%d%d%d", &n, &m, &s, &mod);
for(i = 1; i< = n; i++)scanf("%d", &w[i]);
for(i = 1; i< = n-1; i++){scanf("%d%d", &x, &y); add(x, y); add(y, x); }
build(1, 1, n);
dfs(s, 0);
dfs2(s, s);
for(i = 1; i< = m; i++){
scanf("%d", &g);
if(g == 1){
scanf("%d%d%d", &x, &y, &z);
schange(x, y, z);
}
if(g == 2){
scanf("%d%d", &x, &y);
printf("%d\n", squery(x, y)%mod);
}
if(g == 3){
scanf("%d%d", &x, &y);
change(1, tid[x], tid[e[x]], y);
}
if(g == 4){
scanf("%d", &x);
printf("%d\n", query(1, tid[x], tid[e[x]])%mod);
}
}
return 0;
}
给定n个点以及每个点的权值,要你处理接下来的m个操作。操作有4种。操作从0到3编号。点从1到n编号。
0:后接两个整数(x,y),代表询问从x到y的路径上的点的权值的xor和。保证x到y是联通的。
1:后接两个整数(x,y),代表连接x到y,若x到y已经联通则无需连接。
2:后接两个整数(x,y),代表删除边(x,y),不保证边(x,y)存在。
3:后接两个整数(x,y),代表将点x上的权值变成y。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#define N 300005
using namespace std;
int n,m,top;
int c[N][2],fa[N],v[N],s[N],q[N];
bool rev[N];
//略去快速读入read()
void update(int x){
int l=c[x][0],r=c[x][1];
s[x]=s[l]^s[r]^v[x];
}
void pushdown(int x){
int l=c[x][0],r=c[x][1];
if(rev[x]){
rev[x]^=1;rev[l]^=1;rev[r]^=1;
swap(c[x][0],c[x][1]);
}
}
bool isroot(int x){
return c[fa[x]][0]!=x&&c[fa[x]][1]!=x;
}
void rotate(int x){
int y=fa[x],z=fa[y],l,r;
if(c[y][0]==x)l=0;else l=1;r=l^1;
if(!isroot(y)) {
if(c[z][0]==y)c[z][0]=x;else c[z][1]=x;
}
fa[x]=z;fa[y]=x;fa[c[x][r]]=y;
c[y][l]=c[x][r];c[x][r]=y;
update(y);update(x);
}
void splay(int x){
top=0;q[++top]=x;
for(int i=x;!isroot(i);i=fa[i])
q[++top]=fa[i];
for(int i=top;i;i--)
pushdown(q[i]);
while(!isroot(x)){
int y=fa[x],z=fa[y];
if(!isroot(y))
{
if(c[y][0]==x^c[z][0]==y)rotate(x);
else rotate(y);
}
rotate(x);
}
}
void access(int x){
for(int t=0;x;t=x,x=fa[x])
splay(x),c[x][1]=t,update(x);
}
void makeroot(int x){
access(x);splay(x);rev[x]^=1;
}
int find(int x){
access(x);splay(x);
while(c[x][0])x=c[x][0];
return x;
}
void cut(int x,int y){
makeroot(x);access(y);splay(y);
if(c[y][0]==x)c[y][0]=fa[x]=0;
}
void link(int x,int y){
makeroot(x);fa[x]=y;
}
int main(){
n=read();m=read();
for(int i=1;i<=n;i++)v[i]=read(),s[i]=v[i];
int opt,x,y;
for(int i=1;i<=m;i++){
opt=read();x=read();y=read();
switch(opt){
case 0:makeroot(x);access(y);splay(y);printf("%d\n",s[y]);break;
case 1:if(find(x)!=find(y))link(x,y);break;
case 2:if(find(x)==find(y))cut(x,y);break;
case 3:access(x);splay(x);v[x]=y;update(x);break;
}
}
return 0;
}
给定一棵N个节点的树,每个点有一个权值,对于M个询问(u,v,k),你需要回答u xor lastans和v这两个节点间第K小的点权。其中lastans是上一个询问的答案,初始为0,即第一个询问的u是明文。
nzhtl1477认为这个数据结构应该叫fingertree
#include <iostream>
#include <stdio.h>
#include <vector>
#define ratio 4
#define new_Node(s, v, a, b) (& (* st[ cnt++ ] = Node(s, v, a, b)))
#define merge(a, b) new_Node(a->size + b->size, b->value, a, b)
#define MAXN 100010
using namespace std;
struct Node {
int size, value;
Node * left, * right;
Node(int s, int v, Node * a, Node * b) : size(s), value(v), left(a), right(b) {}
Node() {}
} * null, * root[ MAXN ], * st[4000000], t[4000000];
int n, m, cnt, x, y, k, a[ MAXN ], fa[ MAXN ][20], dep[ MAXN ], ans;
vector < int > linker[ MAXN ];
void insert(int x, Node * cur) {
if(cur->size == 1) {
cur->left = new_Node(1, min(cur->value, x), null, null);
cur->right = new_Node(1, max(cur->value, x), null, null);
}
else insert(x, x > cur->left->value ? cur->right : cur->left);
cur->size++, cur->value = cur->right->value;
}
int rank(int x, Node * cur) {
if(cur->size == 1) return 1;
return x > cur->left->value ? rank(x, cur->right) + cur->left->size : rank(x, cur->left);
}
int find(int x, Node * cur) {
if(cur->size == 1) return cur->value;
return x > cur->left->size ? find(x - cur->left->size, cur->right) : find(x, cur->left);
}
Node * modify(int x, Node * a) {
Node * cur = new_Node(a->size, a->value + 1, a->left, a->right);
if(cur->left)
if(x > cur->left->size) cur->right = modify(x - cur->left->size, cur->right);
else cur->left = modify(x, cur->left);
return cur;
}
int find(int x, Node * a, Node * b, Node * c, Node * d) {
int mid = a->left->value + b->left->value - c->left->value - d->left->value;
if(a->size == 1) return 1;
if(x > mid) return find(x - mid, a->right, b->right, c->right, d->right) + a->left->size;
return find(x, a->left, b->left, c->left, d->left);
}
Node * build(int l, int r) {
if(l == r) return new_Node(1, 0, null, null);
Node * left = build(l, (l + r) >> 1), * right = build(((l + r) >> 1) + 1, r);
return new_Node(r - l + 1, 0, left, right);
}
#define cur linker[x][i]
void dfs(int x) {
root[x] = modify(rank(a[x], root[ n + 1 ]), root[ fa[x][0] ]);
dep[x] = dep[ fa[x][0] ] + 1;
for(int i = 0 ; i < linker[x].size() ; i++)
if(cur != fa[x][0])
fa[ cur ][0] = x, dfs(cur);
}
inline int lca(int x, int y) {
if(dep[x] < dep[y]) swap(x, y);
for(register int i = 0 ; i < 20 ; i++)
if((dep[x] - dep[y]) & (1 << i))
x = fa[x][i];
if(x == y) return x;
for(register int i = 19 ; i >= 0 ; i--)
if(fa[x][i] != fa[y][i])
x = fa[x][i], y = fa[y][i];
return fa[x][0];
}
//略去读入优化read()
inline void addedge(int x, int y) {
linker[x].push_back(y), linker[y].push_back(x);
}
int main() {
n = read(), m = read();
for(register int i = 0 ; i < 4000000 ; i++) st[i] = & t[i];
null = new_Node(0, 0, 0, 0);
root[ n + 1 ] = new_Node(1, 2147483647, null, null);
root[0] = build(1, n);
for(register int i = 1 ; i <= n ; i++) insert(a[i] = read(), root[ n + 1 ]);
for(register int i = 1 ; i < n ; i++) addedge(read(), read());
dfs(1);
for(register int j = 1 ; j < 20 ; j++)
for(register int i = 1 ; i <= n ; i++)
fa[i][j] = fa[ fa[i][j - 1] ][j - 1];
while(m--)
{
x = read() ^ ans, y = read(), k = read();
int l = lca(x, y);
printf("%d", ans = find(find(k, root[x], root[y], root[l], root[ fa[l][0] ]), root[ n + 1 ]));
if(m) putchar('\n');
}
return 0;
}
如题,一开始有N个小根堆,每个堆包含且仅包含一个数。接下来需要支持两种操作:
操作1: 1 x y 将第x个数和第y个数所在的小根堆合并(若第x或第y个数已经被删除或第x和第y个数在用一个堆内,则无视此操作)
操作2: 2 x 输出第x个数所在的堆最小数,并将其删除(若第x个数已经被删除,则输出-1并无视删除操作)
#include<cstdio>
#include<algorithm>
using namespace std;
const int N=101000;
struct Leftist{
int lch,rch,key,fa,dist;
}h[N];
int n,m;
// 省略读入优化read()
int merge(int u,int v){
if (!u || !v)return u+v;
if (h[u].key>h[v].key || (h[u].key==h[v].key && u>v))swap(u,v);
int &ul=h[u].lch,&ur=h[u].rch;
ur=merge(ur,v);
h[ur].fa=u;
if (h[ul].dist<h[ur].dist)swap(ul,ur);
h[u].dist=h[ur].dist+1;
return u;
}
void erase(int u){
int ul=h[u].lch,ur=h[u].rch;
h[u].key=-1;h[ul].fa=0;h[ur].fa=0;
merge(ul,ur);
}
int find(int x){
return h[x].fa?find(h[x].fa):x;
}
int main(){
n=read(),m=read();
h[0].dist=-1;
for (int i=1;i<=n;i++)
h[i].key=read();
for (int i=1;i<=m;i++){
int opt,x,y;
opt=read(),x=read();
if (opt==1){
y=read();
if (h[x].key!=-1 && h[y].key!=-1){
int p=find(x),q=find(y);
if (p!=q)merge(p,q);
}
}else if (opt==2){
if (h[x].key==-1)printf("-1\n");
else{
int p=find(x);
printf("%d\n",h[p].key);
erase(p);
}
}
}
return 0;
}
您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:
这题有多种复杂度不同写法,下面给出的是一个线段树套Treap平衡树的做法。其中的Treap是另外一种写法。
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#pragma GCC optimize("O3")
#define N 50020
#define M 100000000
#define INFINITE 2147483647
using namespace std;
class Node {
public:
Node *s[2];
int v, e, w, z;
Node(int _v, int _e, int _w, int _z) : v(_v), e(_e), w(_w), z(_z){
s[0] = s[1] = NULL;
return;
}
int Size(int k) {
return s[k] ? s[k] -> z : 0;
}
void Update(void) {
z = Size(0) + Size(1) + w;
return;
}
};
class Treap {
public:
Node *r;
void RotateTreap(Node *&x, int k) {
Node *t;
t = x -> s[!k];
x -> s[!k] = t -> s[k];
t -> s[k] = x;
x -> Update();
t -> Update();
x = t;
return;
}
void InsertTreap(Node *&x, int v, int w = 1) {
if(!x)
x = new Node(v, rand(), w, w);
else if(x -> v == v)
x -> w += w;
else if(x -> v < v) {
InsertTreap(x -> s[1], v, w);
if(x -> s[1] -> e < x -> e)
RotateTreap(x, 0);
}
else {
InsertTreap(x -> s[0], v, w);
if(x -> s[0] -> e < x -> e)
RotateTreap(x, 1);
}
x -> Update();
return;
}
void RemoveTreap(Node *&x, int v) {
Node *t;
int k;
if(x -> v == v) {
if(x -> w > 1)
x -> w --;
else {
if(!x -> s[0]) {
t = x;
x = x -> s[1];
delete t;
return;
}
if(!x -> s[1]) {
t = x;
x = x -> s[0];
delete t;
return;
}
k = x -> s[0] -> e < x -> s[1] -> e;
RotateTreap(x, k);
RemoveTreap(x -> s[k], v);
}
}
else {
k = x -> v < v;
RemoveTreap(x -> s[k], v);
if(x -> s[k] && x -> s[k] -> e < x -> e)
RotateTreap(x, x -> s[k] -> e < x -> e);
}
x -> Update();
return;
}
int RankTreap(Node *x, int v) {
int o;
for(o = 0;x;)
if(x -> v == v) {
//printf("G %d\n", x -> Size(0));
return o + x -> Size(0);
}
else if(x -> v < v) {
o += x -> Size(0) + x -> w;
x = x -> s[1];
}
else
x = x -> s[0];
return o;
}
int CountTreap(Node *x, int v) {
while(x) {
if(x -> v == v)
return x -> w;
x = x -> s[x -> v < v];
}
return 0;
}
int PrevTreap(Node *x, int v) {
int o;
for(o = -INFINITE;x;)
if(x -> v >= v)
x = x -> s[0];
else {
o = max(o, x -> v);
x = x -> s[1];
}
return o;
}
int SuffTreap(Node *x, int v) {
int o;
for(o = INFINITE;x;)
if(x -> v <= v)
x = x -> s[1];
else {
o = min(o, x -> v);
x = x -> s[0];
}
return o;
}
void MergeTreap(Node *x) {
if(!x)
return;
MergeTreap(x -> s[0]);
MergeTreap(x -> s[1]);
InsertTreap(r, x -> v, x -> w);
return;
}
};
class Segment {
public:
Treap f[N * 4];
void BuildSegment(int *x, int i, int l, int r) {
if(l >= r) {
f[i].r = NULL;
f[i].InsertTreap(f[i].r, x[l]);
return;
}
BuildSegment(x, i * 2, l, (l + r) / 2);
BuildSegment(x, i * 2 + 1, (l + r) / 2 + 1, r);
f[i].r = NULL;
f[i].MergeTreap(f[i * 2].r);
f[i].MergeTreap(f[i * 2 + 1].r);
/*for(int t = l;t <= r;t ++)
f[i].InsertTreap(f[i].r, x[t]);*/
/*if(f[i * 2].r -> z > f[i * 2 + 1].r -> z) {
f[i] = f[i * 2];
f[i].MergeTreap(f[i * 2 + 1].r);
}
else {
f[i] = f[i * 2 + 1];
f[i].MergeTreap(f[i * 2].r);
}*/
return;
}
int RankSegment(int i, int l, int r, int s, int t, int v) {
if(r < s || l > t)
return 0;
if(l >= s && r <= t)
return f[i].RankTreap(f[i].r, v);
return RankSegment(i * 2, l, (l + r) / 2, s, t, v) + RankSegment(i * 2 + 1, (l + r) / 2 + 1, r, s, t, v);
}
int CountSegment(int i, int l, int r, int s, int t, int v) {
if(r < s || l > t)
return 0;
if(l >= s && r <= t) {
return f[i].RankTreap(f[i].r, v) + f[i].CountTreap(f[i].r, v);
}
return CountSegment(i * 2, l, (l + r) / 2, s, t, v) + CountSegment(i * 2 + 1, (l + r) / 2 + 1, r, s, t, v);
}
int PrevSegment(int i, int l, int r, int s, int t, int v) {
if(r < s || l > t)
return -INFINITE;
if(l >= s && r <= t)
return f[i].PrevTreap(f[i].r, v);
return max(PrevSegment(i * 2, l, (l + r) / 2, s, t, v), PrevSegment(i * 2 + 1, (l + r) / 2 + 1, r, s, t, v));
}
int SuffSegment(int i, int l, int r, int s, int t, int v) {
if(r < s || l > t)
return INFINITE;
if(l >= s && r <= t)
return f[i].SuffTreap(f[i].r, v);
return min(SuffSegment(i * 2, l, (l + r) / 2, s, t, v), SuffSegment(i * 2 + 1, (l + r) / 2 + 1, r, s, t, v));
}
void SetSegment(int *x, int i, int l, int r, int p, int v) {
if(l > p || r < p)
return;
if(l == p && r == p) {
f[i].RemoveTreap(f[i].r, x[p]);
f[i].InsertTreap(f[i].r, v );
return;
}
f[i].RemoveTreap(f[i].r, x[p]);
f[i].InsertTreap(f[i].r, v );
SetSegment(x, i * 2, l, (l + r) / 2, p, v);
SetSegment(x, i * 2 + 1, (l + r) / 2 + 1, r, p, v);
return;
}
int KthSegment(int s, int t, int k, int n, pair<int, int> v) {
int l, m, r;
for(l = v.first - 1, r = v.second;l + 1 < r;) {
//printf("%d : %d\n", (l + r) / 2, CountSegment(1, 0, n - 1, s, t, m = (l + r) / 2));
if(CountSegment(1, 0, n - 1, s, t, m = (l + r) / 2) >= k)
r = m;
else
l = m;
}
return r;
}
};
class Segwin {
private:
int n;
int f[N * 4];
int g[N * 4];
public:
void BuildSegwin(int n, int *x) {
int i;
this -> n = n;
for(i = 0;i < n;i ++)
f[i + n] = g[i + n] = x[i];
for(i = n - 1;i > -1;i --) {
f[i] = min(f[i << 1], f[i << 1 | 1]);
g[i] = max(g[i << 1], g[i << 1 | 1]);
}
return;
}
pair<int, int> MixSegwin(int s, int t) {
pair<int, int> o;
for(o = make_pair(INFINITE, -INFINITE), s += n, t += n + 1;s < t;s >>= 1, t >>= 1) {
if(s & 1) {
o.first = min(o.first , f[s]);
o.second = max(o.second, g[s]);
s ++;
}
if(t & 1) {
t --;
o.first = min(o.first , f[t]);
o.second = max(o.second, g[t]);
}
}
return o;
}
void SetSegwin(int p, int v) {
for(p += n, f[p] = g[p] = v;p >>= 1;) {
f[p] = min(f[p << 1], f[p << 1 | 1]);
g[p] = max(g[p << 1], g[p << 1 | 1]);
}
return;
}
};
int a[N];
Segment f;
Segwin g;
int main() {
int n, m, p, l, r, k;
int i;
scanf("%d %d", &n, &m);
for(i = 0;i < n;i ++)
scanf("%d", &a[i]);
f.BuildSegment(a, 1, 0, n - 1);
g.BuildSegwin(n, a);
while(m --) {
scanf("%d %d %d", &p, &l, &r);
if(p != 3) {
l --;
r --;
scanf("%d", &k);
}
if(p == 1)
printf("%d\n", f.RankSegment(1, 0, n - 1, l, r, k) + 1);
if(p == 2)
printf("%d\n", f.KthSegment(l, r, k, n, /*make_pair(0, M)*/g.MixSegwin(l, r)));
//printf("%d\n", f.CountSegment(1, 0, n - 1, l, r, k));
if(p == 3) {
f.SetSegment(a, 1, 0, n - 1, -- l, r);
g.SetSegwin(l, r);
a[l] = r;
}
if(p == 4)
printf("%d\n", f.PrevSegment(1, 0, n - 1, l, r, k));
if(p == 5)
printf("%d\n", f.SuffSegment(1, 0, n - 1, l, r, k));
}
return 0;
}
n个人,每个人给了一个小写字母'a'到'z'作为编号
一个区间的人如果满足他们的编号重排之后可以成为一个回文串,则他们可以一起回归天空,即这个区间可以回归天空。
给了m个区间,每次求每个区间中有多少个子区间可以回归天空。
#include <iostream>
#include <stdio.h>
#include <vector>
#include <math.h>
#include <algorithm>
#define MAXN 60010
using namespace std;
int n , m , t , block , belong[ MAXN ];
unsigned short cnt[1 << 26];
char s[ MAXN ];
unsigned int a[ MAXN ] , ans[ MAXN ] , res;
struct ask
{
int l , r , pos;
} q[ MAXN ];
inline bool cmp( const ask & a , const ask & b )
{
return belong[ a.l ] ^ belong[ b.l ] ? belong[ a.l ] < belong[ b.l ] : belong[ a.l ] & 1 ? a.r < b.r : a.r > b.r;
}
inline void insert( int x )
{
for( register int i = 0 ; i < t ; i++ )
res += cnt[ x ^ ( 1 << i ) ];
res += cnt[x]++;
}
inline void erase( int x )
{
for( register int i = 0 ; i < t ; i++ )
res -= cnt[ x ^ ( 1 << i ) ];
res -= --cnt[x];
}
inline int read()
{
register int x = 0 , ch = getchar();
while( !isdigit( ch ) ) ch = getchar();
while( isdigit( ch ) ) x = x * 10 + ch - '0' , ch = getchar();
return x;
}
int main()
{
scanf( "%d %d %s" , &n , &m , s + 1 );
for( register int i = 1 ; i <= n ; i++ ) t = max( t , s[i] - 'a' + 1 );
block = n / sqrt( m * 2 / 3 );
for( register int i = 1 ; i <= n ; i++ ) belong[i] = ( i - 1 ) / block , a[i] = a[i - 1] ^ ( 1ll << s[i] - 'a' );
for( register int i = 1 ; i <= m ; i++ )
q[i].l = read() , q[i].r = read() , q[i].pos = i;
sort( q + 1 , q + m + 1 , cmp );
for( int i = 1 , l = 1 , r = 0 ; i <= m ; i++ )
{
while( l > q[i].l ) insert( a[ --l ] );
while( r < q[i].r ) insert( a[ ++r ] );
while( l < q[i].l ) erase( a[ l++ ] );
while( r > q[i].r ) erase( a[ r-- ] );
insert( a[l - 1] );
ans[ q[i].pos ] = res;
erase( a[l - 1] );
}
for( register int i = 1 ; i <= m ; i++ )
printf( "%u\n" , ans[i] );
return 0;
}