临时模板整理

只有一些自己用起来习惯的板。其他的直接抄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();
	}
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值