件名の説明:
ソリューション:
久しぶりの書き込み$ treap $流出のうち。
$ Treap $メンテナンスDP。
この図の三辺に長方形を決定する検討は、少なくとも1つのキー含む数は最初のキーの長方形の開口方向によって決定されます。
このようなグラフは次のようになります。
我々が取ることができる範囲はこれで、次の3つの側面についてのために、ボトムアップからの走査線をやって考えてみましょう:
これは、単に現在についてです。
拡張一見、このようなものがあります。
このプロセスは、ヒープ・トラバーサルのようなものです。
......ヒープの動的なメンテナンスを考えるとないことが判明
しかし、人のようなものが話題を書きました:
したがって、位置=ランダム= Vであります
だから、直接$ Treapは$ =山+ = Vの周りにルートゾーンの多数を維持します
この数字いる間だけ増加したときに、足場の$ X $の$ $ yを$ yを$を変更されたプロパティがあります。
$ Treap $場合にのみ、ノードを変更するように、上向きのターン= V =
コード:
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef long long ll; const int N = 100050; const int M = 40050; template<typename T> inline void read(T&x) { T f = 1,c = 0;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){c=c*10+ch-'0';ch=getchar();} x = f*c; } struct Point { ll x,y; Point(){} Point(ll x,ll y):x(x),y(y){} bool operator < (const Point&a)const{return x!=a.x?x<a.x:y<a.y;} }p[N]; ll r,c,n; struct Treap { int rt,ls[M],rs[M],siz[M]; ll w[M],k[M]; void update(int u) { siz[u] = siz[ls[u]]+siz[rs[u]]+1; w[u] = k[u]*(siz[ls[u]]+1)*(siz[rs[u]]+1)+w[ls[u]]+w[rs[u]]; } void lturn(int&u) { int t = rs[u];rs[u] = ls[t]; ls[t] = u;siz[t] = siz[u]; update(u),update(t);u = t; } void rturn(int&u) { int t = ls[u];ls[u] = rs[t]; rs[t] = u;siz[t] = siz[u]; update(u),update(t);u = t; } void chg(int&u,int qx,ll qw) { if(!u)return ; if(u==qx) { k[u] = qw; update(u); return ; } if(qx<u) { chg(ls[u],qx,qw); if(k[u]<k[ls[u]])rturn(u); }else { chg(rs[u],qx,qw); if(k[u]<k[rs[u]])lturn(u); } update(u); } void build(int l,int r,int&u) { if(l>r)return ; u = (l+r)>>1; build(l,u-1,ls[u]); build(u+1,r,rs[u]); update(u); } }tr; int main() { read(r),read(c),read(n); for(int i=1;i<=n;i++) read(p[i].x),read(p[i].y); tr.build(1,c,tr.rt); sort(p+1,p+1+n); ll ans = 0; for(int i=1,j=1;i<=r;i++) { while(j<=n&&p[j].x==i)tr.chg(tr.rt,p[j].y,i),j++; ans += tr.w[tr.rt]; } printf("%lld\n",ans); return 0; }