只有一些自己用起来习惯的板。其他的直接抄hdu或者红书即可
文章目录
黑科技
最快cdq
void CDQ(int l,int r){
if ( l < r) {
int m = (l + r) >> 1; CDQ(l,m) , CDQ(m + 1,r);
int p1 = l , p2 = m + 1 , p = l;
while ( p1 <= m && p2 <= r ){
if ( q[p1].x < q[p2].x ) modify(q[p1].y) , tmp[p++] = q[p1++];
else query(q[p2].y) , tmp[p++] = q[p2++];
}
while ( p2 <= r ) query(q[p2].y) , tmp[p++] = q[p2++];
for (int i = l ; i < p1 ; i++) clear(q[i].y);
while ( p1 <= m ) tmp[p++] = q[p1++];
for (int i = l ; i <= r ; i++) q[i] = tmp[i];
}
}
字符串
后缀数组
#include<bits/stdc++.h>
using namespace std;
#define maxn 100020
#define rep(i,l,r) for (register int i = l ; i <= r ; i++)
#define repd(i,r,l) for(register int i = r ; i >= l ; i--)
#define lowbit(x) (x&(-x))
typedef long long ll;
//================================SA====================================
int s[maxn],c[maxn],t1[maxn],t2[maxn],sa[maxn],rk[maxn],h[maxn];
int n,a[maxn];
int mn[20][maxn],cnt[maxn];
//sa[i]表示排名为i的后缀的位置,下标从0开始
//rk[i]表示第i个后缀的排名,下标从0开始
//x[i]表示i的第一关键字的权值(排名)
//y[i]表示第二关键字排名为i的后缀的起始位置
//h[i]表示后缀i在排序后与前一位的lcp
//求i,j的lcp是排序后rk[i],rk[j],height的min
//接口,n为串长。字符串读入为s[i],下标从0开始即可
void suffix_array(){
int m = 200 , *x = t1 , *y = t2; //m是值域,如果是字符开200,如果值域是n则开成n
rep(i,0,m) c[i] = 0;
rep(i,0,n - 1) c[x[i] = s[i]]++; //一定要记得把s[n]置位一个分隔位。特别是清空数组时!
rep(i,1,m) c[i] += c[i - 1];
rep(i,0,n - 1) sa[--c[x[i]]] = i;
for (register int k = 1 ; k < n ; k <<= 1){
register int p = 0;
rep(i,0,n - 1) y[i] = 0;
repd(i,n - 1,n - k) y[p++] = i; //必须倒着for,在后面的位置更小
rep(i,0,n - 1) if ( sa[i] >= k ) y[p++] = sa[i] - k;
rep(i,0,m) c[i] = 0;
rep(i,0,n - 1) c[x[y[i]]]++;
rep(i,1,m) c[i] += c[i - 1];
repd(i,n - 1,0) sa[--c[x[y[i]]]] = y[i];
p = 0 , swap(x,y) , x[sa[0]] = ++p;
rep(i,1,n - 1) x[sa[i]] = (y[sa[i]] == y[sa[i - 1]]) && (y[sa[i] + k] == y[sa[i - 1] + k]) ? p : ++p;
if ( p >= n ) break; //如果当前已经完成排名,则break
m = p;
}
rep(i,0,n - 1) rk[sa[i]] = i;
int k = 0;
rep(i,0,n - 1){
if ( !rk[i] ) continue;
int j = sa[rk[i] - 1];
if ( k ) k--;
while ( s[j + k] == s[i + k] ) k++;
h[rk[i]] = k;
}
}
//求两个后缀的最长公共前缀
//在后缀排序后的h数组中用区间RMQ查最小值
void init(){
int k = 0;
rep(i,0,n){
if ( i > (1 << (k + 1)) ) k++;
cnt[i] = k;
}
suffix_array();
rep(i,0,n - 1) mn[0][i] = h[i];
rep(i,1,19)
rep(j,0,n - 1)
if ( j + (1 << (i - 1)) > n || mn[i - 1][j] < mn[i - 1][j + (1 << (i - 1))] ) mn[i][j] = mn[i - 1][j];
else mn[i][j] = mn[i - 1][j + (1 << (i - 1))];
}
inline int lcp(int x,int y){ //x,y是相应的排名
if ( x == y ) return n;
if ( x > y ) swap(x,y);
x++;
int c = cnt[y - x + 1];
return min(mn[c][x],mn[c][y - (1 << c) + 1]);
}
inline int findl(int id,int len){
int l = 0 , r = id , res = id;
while ( l <= r ){
int mid = (l + r) >> 1;
if ( lcp(id,mid) >= len ) res = mid , r = mid - 1;
else l = mid + 1;
}
return res;
}
inline int findr(int id,int len){
int l = id , r = n - 1 , res = id;
while ( l <= r ){
int mid = (l + r) >> 1;
if ( lcp(id,mid) >= len ) res = mid , l = mid + 1;
else r = mid - 1;
}
return res;
}
pr getid(int id,int len){ //查询和id开始的后缀lcp>=len的排名区间
return mp(findl(rk[id],len),findr(rk[id],len));
}
//==============================================================================
后缀自动机
#include<bits/stdc++.h>
using namespace std;
#define maxn 600020
typedef long long ll;
struct SAM{
int next[maxn][26],tot,pnt[maxn],val[maxn],last,sz[maxn];
int a[maxn],b[maxn],jump[20][maxn];
void Add(int x){ //插入一个字符
int np = ++tot ,p = last;
val[np] = val[p] + 1 , sz[np] = 1; //只有np节点有sz
while ( !next[p][x] && p ) next[p][x] = np , p = pnt[p];
int q = next[p][x];
if ( !q ) pnt[np] = p , next[p][x] = np;
else if ( val[p] + 1 == val[q] ) pnt[np] = q;
else{
int nq = ++tot;
val[nq] = val[p] + 1;
pnt[nq] = pnt[q];
pnt[np] = pnt[q] = nq;
memcpy(next[nq],next[q],sizeof(next[q]));
while ( next[p][x] == q && p ) next[p][x] = nq , p = pnt[p];
if ( next[p][x] == q ) next[p][x] = nq;
}
last = np;
}
void getsize(){ //桶排序(相同于拓扑序),求right集合大小
for (int i = 1 ; i <= tot ; i++) a[val[i]]++;
for (int i = 1 ; i <= n ; i++) a[i] += a[i - 1];
for (int i = tot ; i >= 1 ; i--) b[a[val[i]]--] = i;
for (int i = tot ; i >= 1 ; i--) sz[pnt[b[i]]] += sz[b[i]];
}
void pre(){ //预处理倍增
for (int i = 1 ; i <= tot ; i++) jump[0][i] = pnt[i];
for (int i = 1 ; i <= 17 ; i++)
for (int j = 1 ; j <= tot ; j++)
jump[i][j] = jump[i - 1][jump[i - 1][j]];
}
void print(){ //打印
for (int i = 1 ; i <= tot ; i++) cout<<i<<" "<<pnt[i]<<" "<<sz[i]<<endl;
}
}sam;
void init(){
scanf("%s",ch + 1);
for (int i = 1 ; i <= n ; i++) sam.Add(ch[i] - 'a');
sam.getsize();
sam.pre();
// sam.print();
}
int main(){
init();
return 0;
}
数学
多项式
拉格朗日插值法
ll inv[maxn],fac[maxn],f[maxn][maxn],pow_[maxn][maxn],inv_[maxn];
inline void up(ll &x,ll y){ x = (x + y) % mod; }
namespace Lagrange{
struct point{
int x; ll w;
point() { x = 0 , w = 0; }
point(int a,ll b):x(a),w(b){};
}dt[maxn];
typedef vector <ll> Poly;
Poly P; int deg;
void Init(){
P.clear() , P.resize(n + 5);
deg = 0 , P[0] = 1;
}
//分成多项式部分和含重心的部分计算
inline void mul(Poly &P,int a){
++deg;
repd(i,deg,1){
P[i] = (mod - P[i] * a % mod + P[i - 1]) % mod;
}
P[0] = (mod - P[0]) * a % mod;
}
inline void Insert(point a){
mul(P,a.x);
rep(i,1,deg - 1){
dt[i].w = dt[i].w * power(dt[i].x - a.x,mod - 2) % mod;
}
ll curw = a.w;
rep(i,1,deg - 1) curw = power(a.x - dt[i].x,mod - 2) * curw % mod;
dt[deg] = point(a.x,curw);
}
inline ll getval_P(int x){
ll res = 0,curx = 1;
rep(i,0,deg) up(res,curx * P[i]) , curx = curx * x % mod;
return res;
}
inline ll getval_w(int x){
ll res = 0;
rep(i,1,deg) up(res,dt[i].w * power(x - dt[i].x,mod - 2) % mod);
return res;
}
inline ll getval(int x){
//若x是已求的值,则需要直接返回点值,不能代入多项式计算
return getval_P(x) * getval_w(x) % mod;
}
}
using namespace Lagrange;
多项式运算
#include<bits/stdc++.h>
using namespace std;
#define rep(i,l,r) for(register int i = l ; i <= r ; i++)
#define repd(i,r,l) for(register int i = r ; i >= l ; i--)
#define rvc(i,S) for(register int i = 0 ; i < (int)S.size() ; i++)
#define rvcd(i,S) for(register int i = ((int)S.size()) - 1 ; i >= 0 ; i--)
#define fore(i,x)for (register int i = head[x] ; i ; i = e[i].next)
#define forup(i,l,r) for (register int i = l ; i <= r ; i += lowbit(i))
#define fordown(i,id) for (register int i = id ; i ; i -= lowbit(i))
#define pb push_back
#define prev prev_
#define stack stack_
#define mp make_pair
#define fi first
#define se second
#define lowbit(x) ((x)&(-(x)))
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair<int,int> pr;
const int maxn = 200020;
typedef vector <int> poly;
const int mod = 950009857;
//NOTES: 任意乘法需要用mul,或者强制用long long。
//注意取模
//====================================basic operation===============================
inline void add(int &x, int y) {
x += y;
if (x >= mod) {
x -= mod;
}
}
inline void sub(int &x, int y) {
x -= y;
if (x < 0) {
x += mod;
}
}
inline int mul(int x, int y) {
return (int) ((long long) x * y % mod);
}
inline int power(int x, int y) {
int res = 1;
while (y) {
if (y & 1) {
res = mul(res, x);
}
x = mul(x, x);
y >>= 1;
}
return res;
}
inline int inv(int a) {
int b = mod, u = 0, v = 1;
while (a) {
int t = b / a;
b -= t * a;
swap(a, b);
u -= t * v;
swap(u, v);
}
if (u < 0) {
u += mod;
}
return u;
}
//=======================================================================================
namespace ntt {
int base = 1, root = -1, max_base = -1;
poly rev = {0, 1}, roots = {0, 1};
void init() {
int temp = mod - 1;
max_base = 0;
while (temp % 2 == 0) {
temp >>= 1;
++max_base;
}
root = 2;
while (true) {
if (power(root, 1 << max_base) == 1 && power(root, 1 << (max_base - 1)) != 1) {
break;
}
++root;
}
}
void ensure_base(int nbase) { //所有dft需要的预处理
if (max_base == -1) {
init();
}
if (nbase <= base) {
return;
}
assert(nbase <= max_base);
rev.resize(1 << nbase);
for (int i = 0; i < 1 << nbase; ++i) { //预处理翻转位
rev[i] = rev[i >> 1] >> 1 | (i & 1) << (nbase - 1);
}
roots.resize(1 << nbase);
while (base < nbase) { //预处理单位根
int z = power(root, 1 << (max_base - 1 - base));
for (int i = 1 << (base - 1); i < 1 << base; ++i) {
roots[i << 1] = roots[i];
roots[i << 1 | 1] = mul(roots[i], z);
}
++base;
}
}
void dft(poly &a) {
int n = a.size(), zeros = __builtin_ctz(n);
ensure_base(zeros);
int shift = base - zeros;
for (int i = 0; i < n; ++i) {
if (i < rev[i] >> shift) {
swap(a[i], a[rev[i] >> shift]);
}
}
for (int i = 1; i < n; i <<= 1) {
for (int j = 0; j < n; j += i << 1) {
for (int k = 0; k < i; ++k) {
int x = a[j + k], y = mul(a[j + k + i], roots[i + k]);
a[j + k] = (x + y) % mod;
a[j + k + i] = (x + mod - y) % mod;
}
}
}
}
poly multiply(poly a, poly b) {
int need = a.size() + b.size() - 1, nbase = 0;
while (1 << nbase < need) {
++nbase;
}
ensure_base(nbase);
int sz = 1 << nbase;
a.resize(sz);
b.resize(sz);
bool equal = a == b;
dft(a);
if (equal) {
b = a;
} else {
dft(b);
}
int inv_sz = inv(sz);
for (int i = 0; i < sz; ++i) {
a[i] = mul(mul(a[i], b[i]), inv_sz);
}
reverse(a.begin() + 1, a.end()); //相当于NTT(a,-1)
dft(a);
a.resize(need);
return a;
}
poly inverse(poly a) { //常数项不能为0,否则不存在逆元!
int n = a.size(), m = (n + 1) >> 1;
if (n == 1) {
return poly(1, inv(a[0]));
} else {
poly b = inverse(poly(a.begin(), a.begin() + m));
int need = n << 1, nbase = 0;
while (1 << nbase < need) {
++nbase;
}
ensure_base(nbase);
int sz = 1 << nbase;
a.resize(sz);
b.resize(sz);
dft(a);
dft(b);
int inv_sz = inv(sz);
for (int i = 0; i < sz; ++i) {
a[i] = mul(mul(mod + 2 - mul(a[i], b[i]), b[i]), inv_sz);
}
reverse(a.begin() + 1, a.end());
dft(a);
a.resize(n);
return a;
}
}
}
using ntt::multiply;
using ntt::inverse;
poly& operator += (poly &a, const poly &b) {
if (a.size() < b.size()) {
a.resize(b.size());
}
for (int i = 0; i < (int) b.size(); ++i) {
add(a[i], b[i]);
}
return a;
}
poly operator + (const poly &a, const poly &b) {
poly c = a;
return c += b;
}
poly& operator -= (poly &a, const poly &b) {
if (a.size() < b.size()) {
a.resize(b.size());
}
for (int i = 0; i < (int) b.size(); ++i) {
sub(a[i], b[i]);
}
return a;
}
poly operator - (const poly &a, const poly &b) {
poly c = a;
return c -= b;
}
poly& operator *= (poly &a, const poly &b) {
if ((int) min(a.size(), b.size()) < 128) {
poly c = a;
a.assign(a.size() + b.size() - 1, 0);
for (int i = 0; i < (int) c.size(); ++i) {
for (int j = 0; j < (int) b.size(); ++j) {
add(a[i + j], mul(c[i], b[j]));
}
}
} else {
a = multiply(a, b);
}
return a;
}
poly operator * (const poly &a, const poly &b) {
poly c = a;
return c *= b;
}
poly& operator /= (poly &a, const poly &b) {
int n = a.size(), m = b.size();
if (n < m) {
a.clear();
} else {
poly c = b;
reverse(a.begin(), a.end());
reverse(c.begin(), c.end());
c.resize(n - m + 1);
a *= inverse(c);
a.erase(a.begin() + n - m + 1, a.end());
reverse(a.begin(), a.end());
}
return a;
}
poly operator / (const poly &a, const poly &b) {
poly c = a;
return c /= b;
}
poly& operator %= (poly &a, const poly &b) {
int n = a.size(), m = b.size();
if (n >= m) {
poly c = (a / b) * b;
a.resize(m - 1);
for (int i = 0; i < m - 1; ++i) {
sub(a[i], c[i]);
}
}
return a;
}
poly operator % (const poly &a, const poly &b) {
poly c = a;
return c %= b;
}
poly derivative(const poly &a) {
int n = a.size();
poly b(n - 1);
for (int i = 1; i < n; ++i) {
b[i - 1] = mul(a[i], i);
}
return b;
}
poly primitive(const poly &a) {
int n = a.size();
poly b(n + 1), invs(n + 1);
for (int i = 1; i <= n; ++i) {
invs[i] = i == 1 ? 1 : mul(mod - mod / i, invs[mod % i]);
b[i] = mul(a[i - 1], invs[i]);
}
return b;
}
poly logarithm(const poly &a) {
poly b = primitive(derivative(a) * inverse(a));
b.resize(a.size());
return b;
}
poly exponent(const poly &a) {
poly b(1, 1);
while (b.size() < a.size()) {
poly c(a.begin(), a.begin() + min(a.size(), b.size() << 1));
add(c[0], 1);
poly old_b = b;
b.resize(b.size() << 1);
c -= logarithm(b);
c *= old_b;
for (int i = b.size() >> 1; i < (int) b.size(); ++i) {
b[i] = c[i];
}
}
b.resize(a.size());
return b;
}
poly power(const poly &a, int m) { //高端的power写法
int n = a.size(), p = -1;
poly b(n);
for (int i = 0; i < n; ++i) {
if (a[i]) {
p = i;
break;
}
}
if (p == -1) {
b[0] = !m;
return b;
}
if ((long long) m * p >= n) {
return b;
}
int mu = power(a[p], m), di = inv(a[p]);
poly c(n - m * p);
for (int i = 0; i < n - m * p; ++i) {
c[i] = mul(a[i + p], di);
}
c = logarithm(c);
for (int i = 0; i < n - m * p; ++i) {
c[i] = mul(c[i], m);
}
c = exponent(c);
for (int i = 0; i < n - m * p; ++i) {
b[i + m * p] = mul(c[i], mu);
}
return b;
}
poly sqrt(const poly &a) {
poly b(1,(int)sqrt(a[0])); //常数项是完全平方数,如果不是,则需要BSGS开根号
while (b.size() < a.size()) {
poly c(a.begin(), a.begin() + min(a.size(), b.size() << 1));
poly old_b = b;
b.resize(b.size() << 1);
c *= inverse(b);
for (int i = b.size() >> 1; i < (int) b.size(); ++i) {
b[i] = mul(c[i], (mod + 1) >> 1);
}
}
b.resize(a.size());
return b;
}
poly multiply_all(int l, int r, vector<poly > &all) {
if (l > r) {
return poly();
} else if (l == r) {
return all[l];
} else {
int y = (l + r) >> 1;
return multiply_all(l, y, all) * multiply_all(y + 1, r, all);
}
}
poly evaluate(const poly &f, const poly &x) {
int n = x.size();
if (!n) {
return poly();
}
vector<poly> up(n * 2);
for (int i = 0; i < n; ++i) {
up[i + n] = poly{(mod - x[i]) % mod, 1};
}
for (int i = n - 1; i; --i) {
up[i] = up[i << 1] * up[i << 1 | 1];
}
vector<poly> down(n * 2);
down[1] = f % up[1];
for (int i = 2; i < n * 2; ++i) {
down[i] = down[i >> 1] % up[i];
}
poly y(n);
for (int i = 0; i < n; ++i) {
y[i] = down[i + n][0];
}
return y;
}
poly interpolate(const poly &x, const poly &y) {
int n = x.size();
vector<poly> up(n * 2);
for (int i = 0; i < n; ++i) {
up[i + n] = poly{(mod - x[i]) % mod, 1};
}
for (int i = n - 1; i; --i) {
up[i] = up[i << 1] * up[i << 1 | 1];
}
poly a = evaluate(derivative(up[1]), x);
for (int i = 0; i < n; ++i) {
a[i] = mul(y[i], inv(a[i]));
}
vector<poly> down(n * 2);
for (int i = 0; i < n; ++i) {
down[i + n] = poly(1, a[i]);
}
for (int i = n - 1; i; --i) {
down[i] = down[i << 1] * up[i << 1 | 1] + down[i << 1 | 1] * up[i << 1];
}
return down[1];
}
数论
图论
cdq图
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
using namespace std;
#define ll long long
#define MAX 50050
#define inf 1e9
inline int read()
{
int x=0;bool t=false;char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-')t=true,ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
return t?-x:x;
}
struct Line{int u,v,w,id;}E[MAX],St[MAX],e[30][MAX],tmp[MAX];
bool operator<(Line a,Line b){return a.w<b.w;}
struct Query{int x,w;}q[MAX];
int n,m,Q;ll ans[MAX];
int f[MAX],c[MAX],cnt;
int getf(int x){return x==f[x]?x:f[x]=getf(f[x]);}
void init(int x)
{
for(int i=1;i<=x;++i)f[tmp[i].u]=tmp[i].u;
for(int i=1;i<=x;++i)f[tmp[i].v]=tmp[i].v;
}
int W[MAX],size[50];
void Contraction(int &z,ll &Ans)
{
init(z);sort(&tmp[1],&tmp[z+1]);int top=0;
for(int i=1;i<=z;++i)
if(getf(tmp[i].u)!=getf(tmp[i].v))
f[getf(tmp[i].u)]=getf(tmp[i].v),St[++top]=tmp[i];
for(int i=1;i<=top;++i)f[St[i].u]=St[i].u,f[St[i].v]=St[i].v;
for(int i=1;i<=top;++i)//Get the edge must be used
if(St[i].w>-inf)
f[getf(St[i].u)]=getf(St[i].v),Ans+=St[i].w;
top=0;
for(int i=1;i<=z;++i)
if(getf(tmp[i].u)!=getf(tmp[i].v))//Get the edge may be used
{
St[++top]=tmp[i];
c[tmp[i].id]=top;
St[top].u=getf(tmp[i].u);
St[top].v=getf(tmp[i].v);
}
z=top;for(int i=1;i<=top;++i)tmp[i]=St[i];
}
void Reduction(int &z)
{
init(z);sort(&tmp[1],&tmp[z+1]);int top=0;
for(int i=1;i<=z;++i)//Delete the edge will
if(getf(tmp[i].u)!=getf(tmp[i].v))
f[getf(tmp[i].u)]=getf(tmp[i].v),St[++top]=tmp[i],c[tmp[i].id]=top;
else if(tmp[i].w>=inf)St[++top]=tmp[i],c[tmp[i].id]=top;
z=top;for(int i=1;i<=top;++i)tmp[i]=St[i];
}
void CDQ(int l,int r,int dep,ll Ans)
{
if(l==r)W[q[l].x]=q[l].w;//modify
int z=size[dep],mid=(l+r)>>1;
for(int i=1;i<=z;++i)e[dep][i].w=W[e[dep][i].id];
for(int i=1;i<=z;++i)tmp[i]=e[dep][i],c[tmp[i].id]=i;
if(l==r)//Get MST
{
init(z);sort(&tmp[1],&tmp[z+1]);
for(int i=1;i<=z;++i)
if(getf(tmp[i].u)!=getf(tmp[i].v))
f[getf(tmp[i].u)]=getf(tmp[i].v),Ans+=tmp[i].w;
ans[l]=Ans;return;
}
for(int i=l;i<=r;++i)tmp[c[q[i].x]].w=-inf;
Contraction(z,Ans);
for(int i=l;i<=r;++i)tmp[c[q[i].x]].w=+inf;
Reduction(z);
for(int i=1;i<=z;++i)e[dep+1][i]=tmp[i];size[dep+1]=z;
CDQ(l,mid,dep+1,Ans);CDQ(mid+1,r,dep+1,Ans);
}
int main()
{
n=read();m=read();Q=read();
for(int i=1;i<=m;++i)E[i].u=read(),E[i].v=read(),E[i].w=read(),E[i].id=i;
for(int i=1;i<=Q;++i)q[i].x=read(),q[i].w=read();
for(int i=1;i<=m;++i)W[i]=E[i].w;
for(int i=1;i<=m;++i)e[0][i]=E[i];
size[0]=m;CDQ(1,Q,0,0);
for(int i=1;i<=Q;++i)printf("%lld\n",ans[i]);
return 0;
}
统计四元环
void clear(){
rep(i,1,n) adj[i].clear() , graph[i].clear();
}
bool cmp(int x,int y){ return adj[x].size() > adj[y].size(); }
void init(){
rep(i,1,n) order[i] = i;
sort(order + 1,order + n,cmp);
rep(i,1,n) pos[order[i]] = i;
rep(i,1,n){ //度数小的向度数大的连边
for (auto x : adj[i]){
if ( pos[i] > pos[x] ){
graph[i].pb(x);
}
}
}
}
int calc_1(){ //5个点的链(会统计4次四元环,2次三元环+1条边)
int res = 0;
rep(i,1,n){
int sum = 0;
for (auto x : adj[i]){
sub(res,mul(adj[x].size() - 1,adj[x].size() - 1));
add(sum,adj[x].size() - 1);
}
add(res,mul(sum,sum));
}
res = mul(res,inv2);
// cout<<" 一条链 "<<res<<endl;
return res;
}
//异戊烷,会统计两次三元环+1条边
int calc_2(){
int res = 0;
rep(i,1,n){
if ( adj[i].size() <= 2 ) continue;
int coef = (ll)(adj[i].size() - 1) * (adj[i].size() - 2) / 2 % mod;
for (auto x : adj[i]){
add(res,mul(adj[x].size() - 1,coef));
}
}
// cout<<" 异戊烷 "<<res<<endl;
return res;
}
//新戊烷,不会统计到其他东西
int calc_3(){
int res = 0;
rep(i,1,n){
int s = adj[i].size();
if ( s >= 4 ){
add(res,(ll)s * (s - 1) % mod * (s - 2) % mod * (s - 3) % mod * power(24,mod - 2) % mod);
}
}
// cout<<" 新戊烷 "<<res<<endl;
return res;
}
//三元环+1条边和直接就是三元环
int calc_4(){
int res = 0;
rep(i,1,n) vis[i] = 0;
rep(i,1,n){
for (auto x : graph[i]) vis[x] = i;
for (auto x : graph[i]){
for (auto y : graph[x]){
if ( vis[y] == i ){
add(res,adj[x].size() + adj[y].size() + adj[i].size() - 5);
}
}
}
}
// cout<<" 三元环 "<<res<<endl;
return res;
}
//四元环
int calc_5(){
int res = 0;
rep(i,1,n){
for (auto x : adj[i]) for (auto y : graph[x]) vis[y] = 0;
for (auto x : adj[i]){
for (auto y : graph[x]){
if ( y == i || pos[y] > pos[i] ) continue; //注意不能回到自己,且保证统计的y是四元环中最大的点
add(res,vis[y]);
++vis[y];
}
}
}
// cout<<" 四元环 "<<res<<endl;
return res;
}
竞赛图
int e[maxn][maxn];
int n;
int dfn[maxn],low[maxn],ins[maxn],st[maxn],tops,belong[maxn],tot,sz[maxn],dfstime;
int nxt[maxn][maxn],hh[maxn],tt[maxn];
int f[maxn],to[maxn];
vector <int> vec[maxn],P;
void clear(){
rep(i,1,n){
vec[i].clear();
belong[i] = sz[i] = ins[i] = dfn[i] = low[i] = hh[i] = tt[i] = 0;
}
rep(i,1,n) rep(j,1,n) nxt[i][j] = 0;
tops = dfstime = tot = 0;
}
void getpath(int nxt[],int &head,int &tail,const vector <int> &V){
//找哈密顿路径
head = tail = V[0];
nxt[head] = 0;
rep(i,1,V.size() - 1){
int cur = V[i];
if ( e[tail][cur] ) nxt[tail] = cur , tail = cur , nxt[cur] = 0;
else if ( e[cur][head] ) nxt[cur] = head , head = cur;
else{
for (int x = head ; x ; x = nxt[x]){
if ( e[x][cur] && e[cur][nxt[x]] ){
nxt[cur] = nxt[x] , nxt[x] = cur;
break;
}
}
}
}
if ( head == tail ){
nxt[tail] = head;
return;
}
//找哈密顿回路
//找最靠右的和head相连的节点
int id = 0;
for (int x = nxt[head] ; x ; x = nxt[x]){
if ( e[x][head] ) id = x;
}
tail = id , P.clear();
for (int x = nxt[id] ; x ; x = nxt[x]){
P.pb(x);
}
if ( !P.size() ){
nxt[tail] = head;
return;
}
nxt[id] = 0;
int pre = P[0];
//从这个环开始扩大
rvc(i,P){
int cur = P[i],flag = 0;
if ( !pre ) pre = cur;
for (int x = head ; x ; x = nxt[x]){
if ( e[x][pre] && e[cur][nxt[x]] ){
nxt[cur] = nxt[x];
nxt[x] = pre;
flag = 1 , pre = 0;
break;
}
}
// if ( !flag ){
// if ( pre != cur ) nxt[P[i - 1]] = P[i];
// }
}
nxt[tail] = head;
}
void print_Path(int c){
printf("%d ",hh[c]);
for (int x = nxt[c][hh[c]] ; x != hh[c] ; x = nxt[c][x]){
printf("%d ",x);
}
}
void print_Path(int c,int y){
printf("%d ",y);
for (int x = nxt[c][y] ; x != y ; x = nxt[c][x]){
printf("%d ",x);
}
}
网络流
struct node{
int next,to,f;
}e[maxn * 2];
int head[maxn],cnt = 1,cur[maxn];
int q[maxn],hh,tt,S,T,maxflow,dis[maxn],sum;
int deg[maxn],n,m,t,bl;
void clear(){
bl = 1 , cnt = 1;
rep(i,1,T) deg[i] = head[i] = 0;
sum = maxflow = 0;
}
inline void adde(int x,int y,int c){
e[++cnt].to = y;
e[cnt].next = head[x];
e[cnt].f = c;
head[x] = cnt;
e[++cnt].to = x;
e[cnt].next = head[y];
e[cnt].f = 0; //多组数据一定要把每个变量都清空
head[y] = cnt;
}
bool bfs(){
tt = hh = 0;
rep(i,1,T) dis[i] = 0;
dis[S] = 1 , q[tt++] = S; //初值设为1,否则会被迷之更新而死循环,从来没有犯过的错误
while ( hh < tt ){
int x = q[hh++];
for (int i = head[x] ; i ; i = e[i].next){
if ( e[i].f && !dis[e[i].to] ){
dis[e[i].to] = dis[x] + 1;
q[tt++] = e[i].to;
}
}
}
return dis[T];
}
int dfs(int x,int delta){
if ( !delta || x == T ) return delta;
int res = 0;
for (int &i = cur[x] ; i ; i = e[i].next){
if ( e[i].f && dis[e[i].to] == dis[x] + 1 ){
int d = dfs(e[i].to,min(delta,e[i].f));
e[i].f -= d , e[i ^ 1].f += d;
delta -= d, res += d;
if ( !delta ) return res;
}
}
if ( delta ) dis[x] = -1;
return res;
}
费用流
struct node{
int from,next,to,f,ct;
};
node e[maxn * 2];
int head[maxn],cnt = 1;
int maxcost;
int S,T,q[maxn * 20],hh,tt,dis[maxn],inq[maxn],vis[maxn],cur[maxn];
void clear(){
rep(i,1,T) head[i] = 0;
cnt = 1 , maxcost = hh = tt = 0;
//T默认为标号最大的点,边一般不用清空。
//dis和队列在spfa的时候清空
}
inline void adde(int x,int y,int c,int ct){
e[++cnt].to = y;
e[cnt].next = head[x];
e[cnt].from = x;
e[cnt].f = c;
e[cnt].ct = ct;
head[x] = cnt;
e[++cnt].to = x;
e[cnt].next = head[y];
e[cnt].from = y;
e[cnt].f = 0;
e[cnt].ct = -ct;
head[y] = cnt;
}
bool spfa(){
rep(i,1,T) dis[i] = -inf;
tt = hh = 0;
q[tt++] = S , dis[S] = 0;
while ( hh < tt ){
int x = q[hh++];
inq[x] = 0;
fore(i,x){
if ( e[i].f && dis[e[i].to] < dis[x] + e[i].ct ){
dis[e[i].to] = dis[x] + e[i].ct;
if ( !inq[e[i].to] ){
inq[e[i].to] = 1;
q[tt++] = e[i].to;
}
}
}
}
return dis[T] > -inf;
}
int dfs(int x,int delta){
if ( x == T || !delta ) return delta;
int res = 0;
vis[x] = 1;
for (int &i = cur[x] ; i ; i = e[i].next){
if ( !vis[e[i].to] && e[i].f && dis[e[i].to] == dis[x] + e[i].ct ){
int d = dfs(e[i].to,min(delta,e[i].f));
e[i].f -= d , e[i ^ 1].f += d;
delta -= d , res += d;
maxcost += d * e[i].ct;
if ( !delta ){ vis[x] = 0 ; return res; } //每个点不止被访问一次
}
}
if ( delta ) dis[x] = inf;
vis[x] = 0;
return res;
}
void solve(){
while ( spfa() ){
for (int i = 1 ; i <= T ; i++) cur[i] = head[i] , vis[i] = 0; //当前弧不一定需要 , 有时会变慢
int d = dfs(S,inf);
maxflow += d;
}
}
数据结构
点分治
//求一个点周围距离为D的点数
//把在x的联通块考虑x对于fa多算的贡献。维护点分重心树上,每个点到第i层重心的距离
//带修改的动态点分治再套数据结构即可
vector <int> e[maxn];
int tag[maxn];
namespace dianfen{
int dep[20][maxn],fa[maxn];
vector <int> cnt[20][maxn];
int rt,sz[maxn],mx[maxn],tot,layer[maxn],vis[maxn];
void getsize(int x,int fa){
sz[x] = 1 , mx[x] = 0;
for (auto y : e[x]){
if ( vis[y] || y == fa ) continue;
getsize(y,x);
sz[x] += sz[y];
mx[x] = max(mx[x],sz[y]);
}
}
void getroot(int x,int fa){
for (auto y : e[x]){
if ( vis[y] || y == fa ) continue;
getroot(y,x);
}
if ( max(mx[x],tot - sz[x]) < max(mx[rt],tot - sz[rt]) ) rt = x;
}
void maintain(int D,int x,int fa){
if ( tag[x] ){
if ( (int)cnt[D][rt].size() < dep[D][x] + 1 ) cnt[D][rt].resize(dep[D][x] + 1);
cnt[D][rt][dep[D][x]]++;
}
for (auto y : e[x]){
if ( vis[y] || y == fa ) continue;
maintain(D,y,x);
}
}
void getans(int D,int x,int fa){
if ( tag[x] ){
if ( (int)cnt[D][rt].size() < dep[D][x] + 1 ) cnt[D][rt].resize(dep[D][x] + 1);
cnt[D][rt][dep[D][x]]++;
}
for (auto y : e[x]){
if ( vis[y] || y == fa ) continue;
dep[D][y] = dep[D][x] + 1;
getans(D,y,x);
}
}
void divide(int D,int x,int f){
getsize(x,0);
rt = x , tot = sz[x] , getroot(x,0);
if ( f ){
maintain(D - 1,x,f);
for (int i = 1 ; i < (int)cnt[D - 1][rt].size() ; i++) cnt[D - 1][rt][i] += cnt[D - 1][rt][i - 1];
}
dep[D][rt] = 0 , getans(D,rt,0);
for (int i = 1 ; i < (int)cnt[D][rt].size() ; i++) cnt[D][rt][i] += cnt[D][rt][i - 1];
vis[rt] = 1 , fa[rt] = f , layer[rt] = D;
int cur_rt = rt;
for (auto y : e[cur_rt]){
if ( vis[y] ) continue;
divide(D + 1,y,cur_rt);
}
}
int query(int x,int D){
if ( x == -1 ) return 0;
int res = 0 , cur_rt = x;
for (int i = layer[x] ; i >= 0 ; ){
if ( D >= dep[i][x] && cnt[i][cur_rt].size() ) res += cnt[i][cur_rt][min((int)cnt[i][cur_rt].size() - 1,D - dep[i][x])];
if ( !i ) break;
i--;
if ( D >= dep[i][x] && cnt[i][cur_rt].size() ) res -= cnt[i][cur_rt][min((int)cnt[i][cur_rt].size() - 1,D - dep[i][x])];
cur_rt = fa[cur_rt];
}
return res;
}
}
后缀平衡树
#include<bits/stdc++.h>
using namespace std;
#define rep(i,l,r) for(register int i = l ; i <= r ; i++)
#define repd(i,r,l) for(register int i = r ; i >= l ; i--)
#define rvc(i,S) for(register int i = 0 ; i < (int)S.size() ; i++)
#define rvcd(i,S) for(register int i = ((int)S.size()) - 1 ; i >= 0 ; i--)
#define fore(i,x)for (register int i = head[x] ; i ; i = e[i].next)
#define forup(i,l,r) for (register int i = l ; i <= r ; i += lowbit(i))
#define fordown(i,id) for (register int i = id ; i ; i -= lowbit(i))
#define pb push_back
#define prev prev_
#define stack stack_
#define mp make_pair
#define fi first
#define se second
#define lowbit(x) ((x)&(-(x)))
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair<int,int> pr;
const int N = 5e5 + 10;
const int maxn = 100020;
int n,st,rt,cnt,tot,cur[N+5],Void[N+5],m;
const double alpha=0.75;
const ll inf = (1ll << 62);
struct Scapegoat
{
int Son[2],Exist,Size,Fac,ls,rs;
ll L,R,Val;
}node[N+5];
inline void Init()
{
tot=0;
for(register int i=N-1;i;--i) Void[++tot]=i;
}
inline bool balance(int x)
{
return (double)node[x].Fac*alpha>(double)max(node[node[x].Son[0]].Fac,node[node[x].Son[1]].Fac);
}
inline void Build(int x)
{
node[x].Son[0]=node[x].Son[1]=0,node[x].Size=node[x].Fac=1;
}
inline int Insert(int &x,int ls,int rs,ll L,ll R) //L,R是当前的值域区间
{
if(!x)
{
x = Void[tot--];
node[x].ls = ls , node[x].rs = rs , node[x].Val = (L + R) >> 1 , node[x].L = L , node[x].R = R;
node[x].Exist = 1;
Build(x);
return x;
}
if ( node[ls].Val == node[node[x].ls].Val && node[rs].Val == node[node[x].rs].Val ) return x;
++node[x].Size , ++node[x].Fac;
ll mid = (L + R) >> 1;
if(node[ls].Val < node[node[x].ls].Val || (node[ls].Val == node[node[x].ls].Val && node[rs].Val < node[node[x].rs].Val) ) return Insert(node[x].Son[0],ls,rs,L,mid);
return Insert(node[x].Son[1],ls,rs,mid,R);
}
inline void PushUp(int x)
{
node[x].Size=node[node[x].Son[0]].Size+node[node[x].Son[1]].Size+1,node[x].Fac=node[node[x].Son[0]].Fac+node[node[x].Son[1]].Fac+1;
}
inline void Traversal(int x)
{
if(!x) return;
Traversal(node[x].Son[0]);
if(node[x].Exist) cur[++cnt]=x;
else Void[++tot]=x;
Traversal(node[x].Son[1]);
}
inline void SetUp(int l,int r,int &x,ll L,ll R)
{
int mid=l+r>>1;x=cur[mid]; ll Mid = (L + R) >> 1; //记得更新每个节点的区间
node[x].L = L , node[x].R = R , node[x].Val = Mid;
if(l==r)
{
Build(x);
return;
}
if(l<mid) SetUp(l,mid-1,node[x].Son[0],L,Mid);
else node[x].Son[0]=0;
SetUp(mid+1,r,node[x].Son[1],Mid,R),PushUp(x);
}
inline void ReBuild(int &x)
{
cnt=0,Traversal(x);
if(cnt) SetUp(1,cnt,x,node[x].L,node[x].R);
else x=0;
}
inline void check(int x,ll val)
{
int s=val<=node[x].Val?0:1;
while(node[x].Son[s])
{
if(!balance(node[x].Son[s]))
{
ReBuild(node[x].Son[s]);
return;
}
x=node[x].Son[s],s=val<=node[x].Val?0:1;
}
}
inline int get_rank(int v)
{
int x=rt,rk=1;
while(x)
{
if(node[x].Val>=v) x=node[x].Son[0];
else rk+=node[node[x].Son[0]].Fac+node[x].Exist,x=node[x].Son[1];
}
return rk;
}
inline int get_val(int rk)
{
int x=rt;
while(x)
{
if(node[x].Exist&&node[node[x].Son[0]].Fac+1==rk) return node[x].Val;
else if(node[node[x].Son[0]].Fac>=rk) x=node[x].Son[0];
else rk-=node[x].Exist+node[node[x].Son[0]].Fac,x=node[x].Son[1];
}
}
inline void Delete(int &x,int rk) //后缀平衡树一般不用删除
{
if(node[x].Exist&&!((node[node[x].Son[0]].Fac+1)^rk))
{
node[x].Exist=0,--node[x].Fac;
return;
}
--node[x].Fac;
if(node[node[x].Son[0]].Fac+node[x].Exist>=rk) Delete(node[x].Son[0],rk);
else Delete(node[x].Son[1],rk-node[x].Exist-node[node[x].Son[0]].Fac);
}
inline void del(int v)
{
Delete(rt,get_rank(v));
if((double)node[rt].Size*alpha>(double)node[rt].Fac) ReBuild(rt);
}
namespace SGT{
#define ls(x) (x << 1)
#define rs(x) ((x << 1) | 1)
int id[N << 2],a[N];
void build(int x,int l,int r){
if ( l == r ){ id[x] = l; return; }
int mid = (l + r) >> 1;
build(ls(x),l,mid) , build(rs(x),mid + 1,r);
id[x] = l;
}
inline int update(int p1,int p2){
if ( !p1 ) return p2;
if ( !p2 ) return p1;
if ( node[a[p1]].Val > node[a[p2]].Val || (node[a[p1]].Val == node[a[p2]].Val && p1 < p2) ) return p1;
return p2;
}
void modify(int x,int l,int r,int p,int num){
if ( l == r ){
a[l] = num;
id[x] = l;
return;
}
int mid = (l + r) >> 1;
if ( p <= mid ) modify(ls(x),l,mid,p,num);
else modify(rs(x),mid + 1,r,p,num);
id[x] = update(id[ls(x)],id[rs(x)]);
}
int query(int x,int l,int r,int L,int R){
if ( L <= l && R >= r ){
return id[x];
}
int mid = (l + r) >> 1;
int res1 = 0 , res2 = 0;
if ( L <= mid ) res1 = query(ls(x),l,mid,L,R);
if ( R > mid ) res2 = query(rs(x),mid + 1,r,L,R);
return update(res1,res2);
}
}
void init(){
Init();
int cur = Insert(rt,0,0,0,inf);
rep(i,1,n) SGT::a[i] = cur;
SGT::build(1,1,n);
}
int main()
{
// freopen("input.txt","r",stdin);
scanf("%d %d",&n,&m);
init();
while ( m-- ){
char ch[10]; int l,r,k;
scanf("%s",ch);
if ( ch[0] == 'C' ){
scanf("%d %d %d",&l,&r,&k);
st = rt;
int cur = Insert(rt,SGT::a[l],SGT::a[r],0,inf);
check(rt,node[cur].Val);
SGT::a[k] = cur;
SGT::modify(1,1,n,k,cur);
// cout<<"check ";
// rep(i,1,n) cout<<SGT::a[i]<<" "<<node[SGT::a[i]].Val<<endl;
// cout<<endl;
}
else{
scanf("%d %d",&l,&r);
printf("%d\n",SGT::query(1,1,n,l,r));
}
}
}
替罪羊
#include<bits/stdc++.h>
#define N 100000
using namespace std;
int n,st,rt,cnt,tot,cur[N+5],Void[N+5];
const double alpha=0.75;
struct Scapegoat
{
int Son[2],Exist,Val,Size,Fac;
}node[N+5];
inline void Init()
{
tot=0;
for(register int i=N-1;i;--i) Void[++tot]=i; //维护当前的内存池
}
inline bool balance(int x)
{
return (double)node[x].Fac*alpha>(double)max(node[node[x].Son[0]].Fac,node[node[x].Son[1]].Fac);
}
inline void Build(int x)
{
node[x].Son[0]=node[x].Son[1]=0,node[x].Size=node[x].Fac=1;
}
inline void Insert(int &x,int val)
{
if(!x)
{
x=Void[tot--],node[x].Val=val,node[x].Exist=1,Build(x);
return;
}
++node[x].Size,++node[x].Fac; //没有其他update的信息,size直接在这里维护
if(val<=node[x].Val) Insert(node[x].Son[0],val);
else Insert(node[x].Son[1],val);
}
inline void PushUp(int x)
{
node[x].Size=node[node[x].Son[0]].Size+node[node[x].Son[1]].Size+1,node[x].Fac=node[node[x].Son[0]].Fac+node[node[x].Son[1]].Fac+1;
}
inline void Traversal(int x)
{
if(!x) return;
Traversal(node[x].Son[0]);
if(node[x].Exist) cur[++cnt]=x;
else Void[++tot]=x;
Traversal(node[x].Son[1]);
}
inline void SetUp(int l,int r,int &x)
{
int mid=l+r>>1;x=cur[mid];
if(l==r)
{
Build(x);
return;
}
if(l<mid) SetUp(l,mid-1,node[x].Son[0]);
else node[x].Son[0]=0;
SetUp(mid+1,r,node[x].Son[1]),PushUp(x);
}
inline void ReBuild(int &x)
{
cnt=0,Traversal(x);
if(cnt) SetUp(1,cnt,x);
else x=0;
}
inline void check(int x,int val)
{
int s=val<=node[x].Val?0:1;
while(node[x].Son[s])
{
if(!balance(node[x].Son[s]))
{
ReBuild(node[x].Son[s]);
return;
}
x=node[x].Son[s],s=val<=node[x].Val?0:1;
}
}
inline int get_rank(int v)
{
int x=rt,rk=1;
while(x)
{
if(node[x].Val>=v) x=node[x].Son[0];
else rk+=node[node[x].Son[0]].Fac+node[x].Exist,x=node[x].Son[1];
}
return rk;
}
inline int get_val(int rk)
{
int x=rt;
while(x)
{
if(node[x].Exist&&node[node[x].Son[0]].Fac+1==rk) return node[x].Val;
else if(node[node[x].Son[0]].Fac>=rk) x=node[x].Son[0];
else rk-=node[x].Exist+node[node[x].Son[0]].Fac,x=node[x].Son[1];
}
}
inline void Delete(int &x,int rk)
{
if(node[x].Exist&&!((node[node[x].Son[0]].Fac+1)^rk))
{
node[x].Exist=0,--node[x].Fac;
return;
}
--node[x].Fac;
if(node[node[x].Son[0]].Fac+node[x].Exist>=rk) Delete(node[x].Son[0],rk);
else Delete(node[x].Son[1],rk-node[x].Exist-node[node[x].Son[0]].Fac);
}
inline void del(int v)
{
Delete(rt,get_rank(v));
if((double)node[rt].Size*alpha>(double)node[rt].Fac) ReBuild(rt);
}
int main()
{
for(read(n),Init();n;--n)
{
int op,x;read(op),read(x);
switch(op)
{
case 1:st=rt,Insert(rt,x),check(st,x);break; //先插入,再根据插入键值查找要重构的树的位置
case 2:del(x);break;
case 3:write(get_rank(x)),putchar('\n');break;
case 4:write(get_val(x)),putchar('\n');break;
case 5:write(get_val(get_rank(x)-1)),putchar('\n');break;
case 6:write(get_val(get_rank(x+1))),putchar('\n');break;
}
}
return 0;
}
kd-tree
#include<bits/stdc++.h>
using namespace std;
#define rep(i,l,r) for(register int i = l ; i <= r ; i++)
#define repd(i,r,l) for(register int i = r ; i >= l ; i--)
#define rvc(i,S) for(register int i = 0 ; i < (int)S.size() ; i++)
#define rvcd(i,S) for(register int i = ((int)S.size()) - 1 ; i >= 0 ; i--)
#define fore(i,x)for (register int i = head[x] ; i ; i = e[i].next)
#define forup(i,l,r) for (register int i = l ; i <= r ; i += lowbit(i))
#define fordown(i,id) for (register int i = id ; i ; i -= lowbit(i))
#define pb push_back
#define prev prev_
#define stack stack_
#define mp make_pair
#define fi first
#define se second
#define lowbit(x) ((x)&(-(x)))
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
typedef pair<int,int> pr;
const double A=0.8;
const int N=200010,M=1600010;
inline void read(int&a){char c;while(!(((c=getchar())>='0')&&(c<='9')));a=c-'0';while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';}
int n,ans,cmp_d,op,X1,Y1,X2,Y2,k;
int tmp[N],deep,need[N],cnt,cur;
int root;
//size : 子树大小 , 用于重构
struct node{int d[2],l,r,Max[2],Min[2],size,a,sum;}t[N];
inline bool cmp(int a,int b){return t[a].d[cmp_d]<t[b].d[cmp_d];}
inline void umax(int&a,int b){if(a<b)a=b;}
inline void umin(int&a,int b){if(a>b)a=b;}
inline void up(int x){
t[x].size=1+t[t[x].l].size+t[t[x].r].size;
t[x].sum = t[x].a + t[t[x].l].sum + t[t[x].r].sum;
if(t[x].l){
umax(t[x].Max[0],t[t[x].l].Max[0]);
umin(t[x].Min[0],t[t[x].l].Min[0]);
umax(t[x].Max[1],t[t[x].l].Max[1]);
umin(t[x].Min[1],t[t[x].l].Min[1]);
}
if(t[x].r){
umax(t[x].Max[0],t[t[x].r].Max[0]);
umin(t[x].Min[0],t[t[x].r].Min[0]);
umax(t[x].Max[1],t[t[x].r].Max[1]);
umin(t[x].Min[1],t[t[x].r].Min[1]);
}
}
int build(int l,int r,int D){
int mid=(l+r)>>1;
cmp_d=D;
nth_element(need+l+1,need+mid+1,need+r+1,cmp);
int x=need[mid];
t[x].Max[0]=t[x].Min[0]=t[x].d[0];
t[x].Max[1]=t[x].Min[1]=t[x].d[1];
if(l!=mid)t[x].l=build(l,mid-1,!D);else t[x].l=0;
if(r!=mid)t[x].r=build(mid+1,r,!D);else t[x].r=0;
up(x);
return x;
}
void dfs(int x){if(x)need[++cnt]=x,dfs(t[x].l),dfs(t[x].r);}
inline void ins(int&root,int now){
if(!root){root=now;return;}
for(int D=deep=0,x=root;;D^=1){ //非递归的插入,直接边插入边update
tmp[++deep]=x;
umax(t[x].Max[0],t[now].Max[0]);
umax(t[x].Max[1],t[now].Max[1]);
umin(t[x].Min[0],t[now].Min[0]);
umin(t[x].Min[1],t[now].Min[1]);
t[x].size++ , t[x].sum += t[now].a;
if(t[now].d[D]>=t[x].d[D]){
if(!t[x].r){t[x].r=now;break;}else x=t[x].r;
}else{
if(!t[x].l){t[x].l=now;break;}else x=t[x].l;
}
}
tmp[++deep]=now;
if(deep<log(t[root].size)/log(1/A))return;
while((double)t[t[now].l].size<A*t[now].size&&(double)t[t[now].r].size<A*t[now].size)now=tmp[--deep]; //重构
if(!now)return;
if(now==root){
cnt=0,dfs(root);
root=build(1,cnt,0);
return;
}
int y=tmp[--deep];
cnt=0,dfs(now);
int k=build(1,cnt,deep&1);
if(t[y].l==now)t[y].l=k;else t[y].r=k;
}
void ask(int x){
if(!x||t[x].Max[0]<X1||t[x].Min[0]>X2||t[x].Max[1]<Y1||t[x].Min[1]>Y2)return;
if(t[x].Min[0]>=X1&&t[x].Max[0]<=X2&&t[x].Min[1]>=Y1&&t[x].Max[1]<=Y2){ans+=t[x].sum;return;} //ans 是全局变量,也可以改成return ans
if(t[x].d[0]>=X1&&t[x].d[0]<=X2&&t[x].d[1]>=Y1&&t[x].d[1]<=Y2)ans += t[x].a;
ask(t[x].l);ask(t[x].r);
}
int lastans;
int main(){
scanf("%d",&n);
while ( 1 ){
int opt,x,y,A;
read(opt);
if ( opt == 3 ) break;
if ( opt == 1 ){
read(x) , read(y) , read(A);
x ^= lastans , y ^= lastans, A ^= lastans;
++cur;
t[cur].Max[0]=t[cur].Min[0]=t[cur].d[0]=x;
t[cur].Max[1]=t[cur].Min[1]=t[cur].d[1]=y;
t[cur].size = 1 , t[cur].sum = t[cur].a = A;
ins(root,cur);
}
else{
read(X1) , read(Y1) , read(X2) , read(Y2);
X1 ^= lastans , Y1 ^= lastans, X2 ^= lastans , Y2 ^= lastans;
ans = 0 , ask(root);
lastans = ans;
printf("%d\n",lastans);
}
}
}
LCT
struct node{
int x,y;
}e[maxn];
struct node2{
int l,r,id;
bool operator < (node2 a)const{
if ( r == a.r ) return l < a.l;
return r < a.r;
}
};
int T,n,m,q,a[maxn];
struct LCT{
int fa[maxn],mn[maxn],rev[maxn],ch[maxn][2],val[maxn];
node id[maxn],rec[maxn];
int stack_[maxn],tops,tot;
void clear(){
for (int i = 1 ; i <= tot ; i++) fa[i] = rev[i] = ch[i][0] = ch[i][1] = 0;
for (int i = 1 ; i <= n ; i++) val[i] = mn[i] = inf;
tot = n;
}
inline bool isroot(int x){
return (ls(fa[x]) != x) && (rs(fa[x]) != x);
}
inline void reverse(int x){
if ( !x ) return;
swap(ls(x),rs(x));
rev[x] ^= 1;
}
inline void pushdown(int x){
if ( rev[x] ){
reverse(ls(x)) , reverse(rs(x));
rev[x] = 0;
}
}
inline void update(int x){
mn[x] = val[x] , id[x] = rec[x];
if ( ls(x) && mn[ls(x)] < mn[x] ) mn[x] = mn[ls(x)] , id[x] = id[ls(x)];
if ( rs(x) && mn[rs(x)] < mn[x] ) mn[x] = mn[rs(x)] , id[x] = id[rs(x)];
}
inline void rotate(int x){
int y = fa[x],t = rs(y) == x,z = ch[x][1 - t];
if ( !isroot(y) ) ch[fa[y]][rs(fa[y]) == y] = x;
fa[x] = fa[y] , fa[y] = x , ch[x][1 - t] = y;
if ( z ) fa[z] = y;
ch[y][t] = z;
update(y);
}
inline void splay(int x){
tops = 0 , stack_[++tops] = x;
for (int i = x ; !isroot(i) ; i = fa[i]) stack_[++tops] = fa[i];
while ( tops ) pushdown(stack_[tops--]);
while ( !isroot(x) ){
int y = fa[x] , z = fa[y];
if ( !isroot(y) && !((ls(y) == x) ^ (ls(z) == y)) ) rotate(y);
else rotate(x);
if ( isroot(x) ) break;
rotate(x);
}
update(x);
}
inline void access(int x){
int t = 0;
for ( ; x ; x = fa[x] )
splay(x) , ch[x][1] = t , update(x) , t = x;
}
inline void makeroot(int x){
access(x) , splay(x) , reverse(x);
}
inline int findroot(int x){
access(x) , splay(x);
while ( ls(x) ) x = ls(x);
return x;
}
inline void link(int x,int y){
makeroot(x);
makeroot(y) , splay(x) , ch[x][1] = y , fa[y] = x;
update(x);
}
inline int insert(int x,int y,int t){
if ( x == y ) return t;
int p = findroot(x) , q = findroot(y);
if ( p != q ){
++tot , val[tot] = t , rec[tot] = (node){x,y};
link(x,tot) , link(tot,y);
return 0;
}
else{
makeroot(x) , access(y) , splay(x);
int xx = id[x].x , yy = id[x].y , res = mn[x];
makeroot(xx) , access(yy) , splay(xx);
ch[xx][1] = 0 , update(x) , fa[yy] = 0;
++tot , val[tot] = t , rec[tot] = (node){x,y};
link(x,tot) , link(tot,y);
return res;
}
}
inline void cut(int x,int y,int t){
makeroot(x) , access(y) , splay(x);
if ( mn[x] <= t ){
int xx = id[x].x , yy = id[x].y;
makeroot(xx) , access(yy) , splay(xx);
ch[xx][1] = 0 , update(x) , fa[yy] = 0;
}
}
}lct;
合并线段树
ll cur1,cur2,ans;
namespace MergeSeg{
//#define ls(x) (x << 1)
//#define rs(x) ((x << 1) | 1)
//每次合并和修改新建节点,空间nlogn
const int N = 2e5 + 10;
int cnt[N * 30],ls[N * 30],rs[N * 30],tot;
inline void update(int x){
cnt[x] = cnt[ls[x]] + cnt[rs[x]];
}
inline void copy(int c,int x){
cnt[c] = cnt[x] , ls[c] = ls[x] , rs[c] = rs[x];
}
void modify(int &x,int l,int r,int id,int d){
// copy(++tot,x) , x = tot;
if ( !x ) x = ++tot;
if ( l == r ){
cnt[x] += d;
return;
}
int mid = (l + r) >> 1;
if ( id <= mid ) modify(ls[x],l,mid,id,d);
else modify(rs[x],mid + 1,r,id,d);
update(x);
}
/* int merge(int x,int y,int l,int r){
if ( !x && !y ) return 0;
int c = ++tot;
if ( !x ){ copy(c,y); return c; }
if ( !y ){ copy(c,x); return c; }
if ( l == r ){
cnt[c] = cnt[x] + cnt[y];
return c;
}
cur1 += (ll)cnt[rs[x]] * cnt[ls[y]];
cur2 += (ll)cnt[ls[x]] * cnt[rs[y]];
int mid = (l + r) >> 1;
ls[c] = merge(ls[x],ls[y],l,mid);
rs[c] = merge(rs[x],rs[y],mid + 1,r);
update(c);
return c;
}*/
int merge(int x,int y,int l,int r){ //如果不需要保存子树信息用于将来查询则可以不新建节点
if ( !x && !y ) return 0;
if ( !x ){ return y; }
if ( !y ){ return x; }
if ( l == r ){
cnt[x] = cnt[x] + cnt[y];
return x;
}
cur1 += (ll)cnt[rs[x]] * cnt[ls[y]];
cur2 += (ll)cnt[ls[x]] * cnt[rs[y]];
int mid = (l + r) >> 1;
ls[x] = merge(ls[x],ls[y],l,mid);
rs[x] = merge(rs[x],rs[y],mid + 1,r);
update(x);
return x;
}
}
using namespace MergeSeg;
几何
minkovski_sum
#include <bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define per(i,a,b) for(int i=a;i>=b;--i)
#define repd(i,a,b) for(int i=a;i>=b;--i)
#define rvc(i,S) for(int i=0;i<(int)S.size();++i)
#define fore(i,x) for(int i = head[x] ; i ; i = e[i].next)
#define mp make_pair
#define pb push_back
#define fi first
#define se second
#define debug(...) fprintf(stderr,__VA_ARGS__)
using namespace std;
typedef long long ll;
#define maxn 100020
struct point{
int x,y;
bool operator < (point a)const{
if ( x == a.x ) return y < a.y;
return x < a.x;
/* if ( y == a.y ) return x < a.x;
return y < a.y;*/
}
bool operator == (point a)const{
return x == a.x && y == a.y;
}
point(){};
point(int a,int b):x(a),y(b){};
point operator - (point a){
return point(x - a.x,y - a.y);
}
point operator + (point a){
return point(x + a.x,y + a.y);
}
int norm(){
return x * x + y * y;
}
};
struct line{
point a,b;
line(){};
line(point x,point y):a(x),b(y){};
};
inline int det(point a,point b){ return a.x * b.y - a.y * b.x; }
inline int dot(point a,point b){ return a.x * b.x + a.y * b.y; }
inline int dist(point a,point b){ return (a - b).norm(); }
vector <point> a,b,c;
vector <point> dt[120];
int n,ans;
void convex_hull(vector <point> &a){
vector <point> res;
if ( !a.size() ) return;
sort(a.begin(),a.end());
a.erase(unique(a.begin(),a.end()),a.end());
res.resize(2 * a.size() + 5);
int m = 0;
rvc(i,a){
while ( m > 1 && det(res[m - 1] - res[m - 2],a[i] - res[m - 2]) <= 0 ) --m;
res[m++] = a[i];
}
int k = m;
repd(i,(int)(a.size() - 2),0){
while ( m > k && det(res[m - 1] - res[m - 2],a[i] - res[m - 2]) <= 0 ) --m;
res[m++] = a[i];
}
res.resize(m);
// if ( a.size() > 1 ) res.resize(m - 1);
a = res;
}
int cal(point p){
int x = p.x , y = p.y;
if ( x >= 0 ){
if ( y >= 0 ) return 1;
return 0;
}
if ( y >= 0 ) return 2;
return 3;
}
void getans(){
c.clear();
c.resize(a.size() + b.size() + 5);
/*rvc(i,a){
cout<<a[i].x<<" "<<a[i].y<<endl;
}
cout<<endl;
rvc(i,b){
cout<<b[i].x<<" "<<b[i].y<<endl;
}
cout<<endl;*/
c[0] = a[0] + b[0];
ans = max(ans,c[0].norm());
int n = a.size() , m = b.size() , pn = 0 , pm = 0;
rep(i,1,n + m - 2){
if ( pn == n - 1 ){
point tmp = b[pm + 1] - b[pm]; pm++;
c[i] = c[i - 1] + tmp;
}
else if ( pm == m - 1 ){
point tmp = a[pn + 1] - a[pn]; pn++;
c[i] = c[i - 1] + tmp;
}
else{
point tmp = a[pn + 1] - a[pn] , tnp = b[pm + 1] - b[pm];
if (cal(tmp) < cal(tnp) || (cal(tmp) == cal(tnp) && (det(tmp,tnp) >= 0)) ) c[i] = c[i - 1] + tmp , pn++;
else c[i] = c[i - 1] + tnp , pm++;//
}
ans = max(ans,c[i].norm());
}
/*rep(i,0,n + m - 2){
cout<<c[i].x<<" "<<c[i].y<<" "<<c[i].norm()<<endl;
}
cout<<endl;*/
}
void solve(int l,int r){
if ( l == r ) return;
int mid = (l + r) >> 1;
solve(l,mid) , solve(mid + 1,r);
a.clear() , b.clear();
rep(i,l,mid){
rvc(j,dt[i]){
a.pb(dt[i][j]);
}
}
convex_hull(a);
rep(i,mid + 1,r){
rvc(j,dt[i]){
b.pb(point(-dt[i][j].x,-dt[i][j].y));
}
}
convex_hull(b);
if ( a.size() && b.size() ) getans(); //minkovski
}
int main(){
freopen("k.in","r",stdin);
//freopen("input.txt","r",stdin);
freopen("1.out","w",stdout);
int t = 0;
while ( 1 ){
++t;
scanf("%d",&n);
if ( !n ) break;
int mx = 0;
rep(i,1,n){
int x,y,k;
scanf("%d %d %d",&x,&y,&k);
dt[k].pb(point(x,y));
mx = max(mx,k);
}
solve(0,mx);
printf("%d\n",ans);
ans = 0;
rep(i,0,mx) dt[i].clear();
}
}