zoukankan      html  css  js  c++  java
  • 【2021省选前夕总结】

    网络流

    DinIc:

    queue<int>QWQ;
    
    ll bfs(){
    	flow = 0;
    	memset(minn,127,sizeof(minn));
    	memset(pre,0,sizeof(pre));
    	memset(vis,0,sizeof(vis));	
    	QWQ.push(s);
    	while(!QWQ.empty()){
    		ll now = QWQ.front();
    		//std::cout<<now<<std::endl;
    		QWQ.pop();
    		if(now == t)
    		break;
    		for(int i = head[now];i;i = e[i].next){
    			ll vi = e[i].to;
    			//std::cout<<vi<<" ";
    			if(!vis[vi] && e[i].v && vi != pre[now]){
    				QWQ.push(vi);
    				pre[vi] = now;
    				minn[vi] = std::min(minn[now],e[i].v);
    				vis[vi] = 1;
    			}
    		}
    		//puts("");
    	}
    	while(!QWQ.empty())
    	QWQ.pop();
    	if(!vis[t])
    	return 0;
    	ll now = t,cut = minn[t];
    //	std::cout<<cut<<std::endl;
    //	puts("");
    	while(now != s){
    		for(int i = head[now];i;i = e[i].next){
    			if(e[i].to == pre[now]){
    				e[i].v += cut;
    				e[i ^ 1].v -= cut;
    				break;
    			}
    		}
    		now = pre[now];
    	}
    	return flow = cut;
    }
    

    EK费用流

    bool spfa(){
    	std::queue<int>QWQ;
    	for(int i = 1;i <= n;++i){
    		minc[i] = 0x3f3f3f3f,vis[i] = 0;
    	}
    	QWQ.push(s);
    	vis[s] = 1;
    	minw[s] = 0x3f3f3f3f;
    	minc[s] = 0;
    	while(!QWQ.empty()){
    		int now = QWQ.front();
    		QWQ.pop();
    		vis[now] = 0;
    		for(int i = head[now];i;i = e[i].next){
    			if(e[i].v){
    				int v = e[i].to;
    				if(minc[v] > minc[now] + e[i].c){
    					minc[v] = minc[now] + e[i].c;
    					pre[v] = i;
    					minw[v] = std::min(minw[now],e[i].v);
    					if(!vis[v])vis[v] = 1,QWQ.push(v);
    				}
    			}
    		}
    	}
    	return minc[t] != 0x3f3f3f3f;
    }
    
    int answ,ansc;
    
    void up(){
    	int now = t;
    	answ += minw[t];
    	ansc += minc[t] * minw[t];
     	while(now != s){
    		e[pre[now]].v -= minw[t];
    		e[pre[now] ^ 1].v += minw[t];
    		now = e[pre[now] ^ 1].to;
    	}
    }
    

    \(tarjan缩点\ 30min\)
    每天一个抱铃小技巧:low[u] == std::min(low[u],dfn[v]);这个居然不会报错
    割点:仿照强连通分量,判断条件改为 low[v]>=dfn[u](v是搜索树上新根)
    割边:仿照强连通分量,判断条件改为 low[v]>dfn[u]
    无向图注意由于是维护的搜索树,不要搜到父亲去,割点时,如果搜索树根只是一个儿节点(搜索树上的),那么要强制把他设为非割点。

    数据结构

    胆大心细,暴力操作。
    平衡树/线段树五问:
    1.每个节点需要记录那些信息
    2.需要那些标记
    3.下传标记怎么做
    4.区间整体修改怎么搞
    5.如何合并区间

    Fhq_treap

    ll ch[A][2],val[A],cv[A],siz[A],cnt;
    #define l(x) ch[x][0]
    #define r(x) ch[x][1]
    #define v(x) val[x]
    #define c(x) cv[x]
    #define s(x) siz[x]
    
    void up(ll x){s(x) = 1 + s(l(x)) + s(r(x));}
    
    ll randoom(){return rand() << 15 | rand();}
    
    ll newcode(ll x){s(++cnt) = 1,v(cnt) = x,c(cnt) = randoom();return cnt;}
    
    void split(ll now,ll k,ll &x,ll &y){
    	if(!now){x = y = 0;return;}
    	if(v(now) <= k) x = now,split(r(now),k,r(now),y);
    	else
    	y = now,split(l(now),k,x,l(now));
    	up(now);
    }
    
    ll merge(ll x,ll y){
    	if(!x || !y)return x + y;
    	if(c(x) < c(y)){
    		r(x) = merge(r(x),y);
    		up(x);return x;
    	}
    	else{
    		l(y) = merge(x,l(y));
    		up(y);return y;
    	}
    }
    
    ll root,x,y,z,cn;
    
    void insert(ll a){
    	cn ++ ;
    	split(root,a,x,y);
    	root = merge(merge(x,newcode(a)),y);
    }
    
    void del(ll a){
    	cn -- ;
    	split(root,a,x,z);
    	split(x,a - 1,x,y);
    	y = merge(l(y),r(y));
    	root = merge(x,merge(y,z));
    }
    
    ll find(ll a){
    	split(root,a - 1,x,y);
    	ll ans = s(x) + 1;
    	root = merge(x,y);
    	return ans;
    }
    
    ll kth(ll now,ll k){
    	if(k <= s(l(now)))return kth(l(now),k);
    	else
    	if(k == s(l(now)) + 1)return now;
    	else
    	return kth(r(now),k - s(l(now)) - 1);
    }
    

    主席树:

    ll build(ll l,ll r){
       ll now = ++cnt;
       if(l == r){
       	tree[now].va = 0;
        return now;
       }
       tree[now].l = build(l,mid);
       tree[now].r = build(mid + 1,r);
       return now;
    }
    
    ll up(ll now){
       tree[now].va = tree[tree[now].l].va + tree[tree[now].r].va;
    }
    
    ll update(ll pre,ll l,ll r,ll k){
       ll now = ++cnt;
       tree[now].l = tree[pre].l;
       tree[now].r = tree[pre].r;
       tree[now].va = tree[pre].va + 1;
       if(l < r)
       if(k <= mid)
       tree[now].l = update(tree[pre].l,l,mid,k);
       else
       tree[now].r = update(tree[pre].r,mid + 1,r,k);
       return now;
    }
    
    ll query(ll u,ll v,ll l,ll r,ll k){
    	if(l >= r) return l;
    	//std::cout<<u<<" "<<v<<" "<<tree[tree[v].l].va<<" "<<tree[tree[u].l].va<<std::endl;
    	ll x = tree[tree[v].l].va - tree[tree[u].l].va;
    	if(x >= k) return query(tree[u].l,tree[v].l,l,mid,k);
    	else return query(tree[u].r,tree[v].r,mid + 1,r,k - x);
    } //静态区间kth
    

    线段树合并:

    int merge(int a,int b,int x,int y) {
    	if(!a) return b;if(!b) return a;
    	if(x==y) {d[a]+=d[b];t[a]=x;return a;}
    	int mid=x+y>>1;
    	l[a]=merge(l[a],l[b],x,mid),r[a]=merge(r[a],r[b],mid+1,y);
    	pushup(a);return a;
    }//破坏结构,省空间,离线
    
    int merge(int a,int b,int x,int y) {
    	if(!a) return b;if(!b) return a;
    	int root=++cnt;
    	if(x==y) {d[root]=d[a]+d[b];t[root]=x;return root;}
    	int mid=x+y>>1;
    	l[root]=merge(l[a],l[b],x,mid),r[root]=merge(r[a],r[b],mid+1,y);
    	pushup(root);return root;
    }//类似于主席树,炸空间
    

    cdq分治:

    struct P{
    	ll x,y,z,id;
    }e[N];
    
    ll ans[N],unq[N],f[N];
    ll t[N * 2];
    
    ll n,k;
    
    void add(ll x,ll p){
    	for(int i = x;i <= k;i += lowbit(i))
    	t[i] += p;
    }
    
    int get(ll x){
    	ll ans = 0;
    	for(int i = x;i;i -= lowbit(i))
    	ans += t[i];
    	return ans;
    }
    
    bool cmp(P t,P s){
    	if(t.x != s.x)
    	return t.x < s.x;
    	if(t.y != s.y)
    	return t.y < s.y;
    	return t.z < s.z;
    }
    
    bool cmp1(P t,P s){
    	if(t.y != s.y)
    	return t.y < s.y;
    	if(t.z != s.z)
    	return t.z < s.z;	
    	return t.x < s.x;
    }
    
    void cdq(ll l,ll r){
    	if(l == r)
    	return;
    	int mid = (l + r) >> 1;
    	cdq(l,mid),cdq(mid + 1,r);
    	std::sort(e + l,e + r + 1,cmp1);
    	for(int i = l;i <= r;++i)
    	if(e[i].x <= mid)
    	add(e[i].z,1);
    	else
    	ans[e[i].id] += get(e[i].z);
    	for(int i = l;i <= r;++i){
    	if(e[i].x <= mid)
    	add(e[i].z,-1);
    //	printf("%lld %lld\n",e[i].x,ans[e[i].id]);
    	}
    }
    
    int main(){
    	scanf("%lld%lld",&n,&k);
    	for(int i = 1;i <= n;++i)
    	scanf("%lld%lld%lld",&e[i].x,&e[i].y,&e[i].z),e[i].id = i;
    	std::sort(e + 1,e + n + 1,cmp);
    	for(int i = 1,j;i <= n;){
    		j = i + 1;
    		while(j <= n && e[j].x == e[i].x && e[j].y == e[i].y && e[j].z == e[i].z)
    		j ++ ;
    		while(i < j)
    		unq[e[i].id] = e[j - 1].id,i ++ ;
    	}
    	for(int i = 1;i <= n;++i)
    	e[i].x = i;
    	cdq(1,n);
    	for(int i = 1;i <= n;++i)
    	f[ans[unq[e[i].id]]] ++ ;
    	for(int i = 0;i < n;++i)
    	printf("%lld\n",f[i]);
    } 
    

    01tire什么的就不写的,到时候复习一点笔记好了

    数论

    exgcd

    LL exgcd(LL a,LL b,LL &x,LL &y){
    	LL d=a; if(b==0) x=1,y=0; else{
    		d=exgcd(b,a%b,y,x),y-=a/b*x;
    	}
    	return d;
    }
    

    筛法:

    	mu[1] = 1;
    	for(int i = 2;i <= 10000000;++i){
    		if(!flag[i]) prime[++cnt] = i,mu[i] = -1,phi[i] = i - 1;
    		for(int j = 1;j <= cnt && i * prime[j] <= 10000000;++j){
    			flag[i * prime[j]] = 1;
    			if(i % prime[j] == 0){phi[i * prime[j]] = phi[i] * prime[j];break;}
    			phi[i * prime[j]] = phi[i] * (prime[j] - 1);
    			mu[i * prime[j]] = -mu[i];
    		}
    	}
    

    杜教筛

    到时候看博客

    字符串

    马拉车

    	s[0] = '~';
    	a = getchar();
    	while(a <= 'z' && a >= 'a'){
    		s[++len] = '|';
    		s[++len] = a;
    		a = getchar();
    	}
    	s[++len] = '|';
    	for(int i = 1;i <= len;++i){
    		if(m + ans[m] >= i)
    		ans[i] = std::min(m + ans[m] - i,ans[m * 2 - i]);
    		while(s[i - ans[i]] == s[i + ans[i]]) ans[i] ++ ;
    		if(ans[i] + i > m + ans[m])m = i;
    		if(fans < ans[i])
    		fans = ans[i];
    	} 
    	std::cout<<fans - 1;
    

    最小表示法

    	scanf("%lld",&n);
    	for(int i = 1;i <= n;++i)
    	scanf("%lld",&a[i]);
    	for(int i = n + 1;i <= 2 * n;++i)
    	a[i] = a[i - n];
    	int j = 1,i = 2,k,tmp;
    	while(i <= n){
    		k = 0;
    		while(a[i + k] == a[j + k])
    		k += 1;
    		if(a[i + k] < a[j + k])
    		tmp = i,i = std::max(i + 1,j + k + 1),j = tmp;
    		else
    		i = i + k + 1;
    	}
    	for(int l = 1;l <= n;++l)
    	std::cout<<a[j + l - 1]<<" ";
    

    AC自动机

    ll n,cnt;
    int to[1000005][50],end[1000005],fail[1000005];
    char a[1000005];
    
    void insert(){
    	ll now = 0;
    	ll n = strlen(a + 1);
    	for(int i = 1;i <= n;++i){
    		if(!to[now][a[i] - 'a'])
    		to[now][a[i] - 'a'] = ++ cnt ;
    		now = to[now][a[i] - 'a'];
    	}
    	end[now] ++ ;
    }
    
    std::queue<int>	QWQ ;
    
    void get(){
    	for(int i = 0;i < 26;++i)
    	if(to[0][i]) fail[to[0][i]] = 0,QWQ.push(to[0][i]);
    	while(! QWQ.empty()){
    		ll u = QWQ.front();QWQ.pop();
    		for(int i = 0;i < 26;++i)
    		if(to[u][i]) fail[to[u][i]] = to[fail[u]][i],QWQ.push(to[u][i]);
    		else to[u][i] = to[fail[u]][i]; 
    	}
    }
    
    int query(){
    	ll len = strlen(a + 1),now = 0,ans = 0;
    	for(int i = 1;i <= len;++i){
    		now = to[now][a[i] - 'a'];
    		for(int t = now;t && end[t] != -1;t = fail[t]) ans += end[t],end[t] = -1;
    	}
    	return ans;
    }
    

    SA:

    const int maxn = 1e6 + 5;
    int rk[maxn], RK[maxn];
    int sa[maxn], SA[maxn];
    int bac[maxn], n, h[maxn], height[maxn];
    int rmq[maxn][18], bin[1 << 18];
    char str[maxn];
    
    void getsa(char *str, int n, int alp = 256) {
        for (int i = 0; i <= alp; i++) bac[i] = 0;
        for (int i = 1; i <= n; i++) ++bac[str[i]];
        for (int i = 1; i <= alp; i++) bac[i] += bac[i - 1];
        for (int i = 1; i <= n; i++) sa[bac[str[i]]--] = i;
        for (int i = 1; i <= n; i++) rk[sa[i]] = rk[sa[i - 1]] + (str[sa[i]] != str[sa[i - 1]]);
    
        for (int p = 1; p <= n; p <<= 1)
        {
            for (int i = 1; i <= n; i++) bac[rk[sa[i]]] = i;
            for (int i = n; i >= 1; i--) if (sa[i] > p) SA[bac[rk[sa[i] - p]]--] = sa[i] - p;
            for (int i = n; i > n - p; i--) SA[bac[rk[i]]--] = i;
            #define comp(x, y) (rk[x] != rk[y] || rk[x + p] != rk[y + p])
            for (int i = 1; i <= n; i++) RK[SA[i]] = RK[SA[i - 1]] + comp(SA[i], SA[i - 1]);
            for (int i = 1; i <= n; i++) sa[i] = SA[i], rk[i] = RK[i];
            if (rk[sa[n]] >= n) return ;
        }
    }
    void geth(char *str, int n) {
        for (int i = 1; i <= n; i++)
        {
            int j = sa[rk[i] - 1], k = max(0, h[i - 1] - 1);
            while (str[i + k] == str[j + k] && str[i + k]) ++k;
            h[i] = height[rk[i]] = k;
        }
        for (int j = 0; j < 18; j++)
        for (int i = 1 << j; i < (1 << j + 1); i++) bin[i] = j;
        for (int i = 1; i <= n; i++) rmq[i][0] = height[i];
        for (int j = 1; j < 18; j++)
        for (int i = 1 << j; i <= n; i++)
            rmq[i][j] = min(rmq[i - (1 << j - 1)][j - 1], rmq[i][j - 1]);
    }
    int lcp(int x, int y) {
        int u = rk[x], v = rk[y];
        if (u > v) swap(u, v);
        int j = bin[v - u];
        return min(rmq[v][j], rmq[u + (1 << j)][j]);
    }
    

    树上问题

    树链剖分

    ll n,m,root,p;
    ll v[200000],head[200000];
    ll cnt = 0;
    
    void add(ll x,ll y){
    	e[++cnt].to = y;
    	e[cnt].next = head[x];
    	head[x] = cnt;
    }
    
    int dep[200000],fa[200000],siz[200000],gson[200000];
    
    int dfncnt,dfn[200000],top[200000],num[200000];
    
    void dfs2(int u,int t){
    	top[u] = t;
    	dfn[u] = ++dfncnt;
    	num[dfncnt] = v[u];
    	if(!gson[u])return;
    	dfs2(gson[u],t);
    	for(int i = head[u];i;i = e[i].next){
    		int v = e[i].to;
    		if(v == fa[u] || v == gson[u])
    		continue;
    		dfs2(v,v);
    	}
    }
    
    void dfs(ll u,ll f){
    	fa[u] = f;
    	dep[u] = dep[f] + 1;
    	siz[u] = 1;
    	for(int i = head[u];i;i = e[i].next){
    		int v = e[i].to;
    		if(v == f)
    		continue;
    		dfs(v,u);
    		siz[u] += siz[v];
    		if(siz[v] > siz[gson[u]])
    		gson[u] = v;
    	}
    }
    
    struct Seg{
    	struct E{
    		ll l,r,v,m;
    	}t[400000];
    	#define l(x) t[x].l
    	#define r(x) t[x].r
    	#define v(x) t[x].v
    	#define m(x) t[x].m
    	#define mid ((l + r) >> 1)
    	void up(ll now){v(now) = (v(l(now)) + v(r(now))) % p;}
    	void push(ll now,ll l,ll r){
    	m(l(now)) += m(now);
    	m(r(now)) += m(now);
    	v(l(now)) += m(now) * (mid - l + 1);
    	v(r(now)) += m(now) * (r - mid);
    	v(l(now)) %= p,m(l(now)) %= p;
    	v(r(now)) %= p,m(r(now)) %= p;
    	m(now) = 0;}
    	ll build(ll l,ll r){
    		ll now = ++cnt;
    		m(now) = 0;
    		if(l == r){
    			v(now) = num[l];
    			return cnt;
    		}
    		l(now) = build(l,mid);
    		r(now) = build(mid + 1,r);
    		up(now);
    		return now;
    	}
    	void change(ll now,ll l,ll r,ll nl,ll nr,ll s){
    		push(now,l,r);
    		if(nl <= l && r <= nr){
    			v(now) += (r - l + 1) * s;
    			m(now) += s;
    			v(now) %= p;
    			m(now) %= p;
    			return ;
    		}
    		if(nl <= mid)
    			change(l(now),l,mid,nl,nr,s);
    		if(nr > mid)
    			change(r(now),mid + 1,r,nl,nr,s);
    		up(now);
    	}
    	ll q(ll now,ll l,ll r,ll nl,ll nr){
    		push(now,l,r);
    		ll ans = 0;
    		if(nl <= l && r <= nr)
    		return v(now) % p;
    		if(nl <= mid)
    		ans = (ans + q(l(now),l,mid,nl,nr)) % p;
    		if(nr > mid)
    		ans = (ans + q(r(now),mid + 1,r,nl,nr)) % p;
    		up(now);
    		return ans;
    	}
    }Q;
    
    int main(){
    	scanf("%lld%lld%lld%lld",&n,&m,&root,&p);
    	for(int i = 1;i <= n;++i){
    		scanf("%lld",&v[i]);
    	}
    	for(int i = 1;i <= n - 1;++i){
    		ll x,y;
    		scanf("%lld%lld",&x,&y);
    		add(x,y);
    		add(y,x);
    	}
    	dfs(root,0);
    	dfs2(root,root);
    	cnt = 0;
    	int z = Q.build(1,n);
    //	for(int i = 1;i <= n;++i){
    //		std::cout<<fa[i]<<" "<<dep[i]<<" "<<top[i]<<" "<<dfn[i]<<" "<<siz[i]<<" "<<gson[i]<<std::endl;
    //	}
    	for(int i = 1;i <= m;++i){
    		ll opt,x,y,z;
    		scanf("%lld",&opt);
    		if(opt == 1){
    			scanf("%lld%lld%lld",&x,&y,&z);
    			z %= p;
    			while(top[x] != top[y]){
    				if(dep[top[x]] < dep[top[y]])std::swap(x,y);
    				Q.change(1,1,n,dfn[top[x]],dfn[x],z);
    				x = fa[top[x]];
    			}
    			if(dep[x] > dep[y]) std::swap(x,y);
    			Q.change(1,1,n,dfn[x],dfn[y],z);
    		}
    		if(opt == 2){
    			scanf("%lld%lld",&x,&y);
    			ll ans = 0;
    			while(top[x] != top[y]){
    				if(dep[top[x]] < dep[top[y]])std::swap(x,y);
    				ans = (ans + Q.q(1,1,n,dfn[top[x]],dfn[x])) % p;
    				x = fa[top[x]];
    			}
    			if(dep[x] > dep[y])
    			std::swap(x,y);
    			ans = (ans + Q.q(1,1,n,dfn[x],dfn[y])) % p;
    			std::cout<<ans % p<<std::endl;
    		}
    		if(opt == 3){
    			scanf("%lld%lld",&x,&z);
    			Q.change(1,1,n,dfn[x],dfn[x] + siz[x] - 1,z);
    		}
    		if(opt == 4){
    			scanf("%lld",&x);
    			std::cout<<Q.q(1,1,n,dfn[x],dfn[x] + siz[x] - 1) % p<<std::endl;
    		}
    	}
    }//一个普通的维护路径权和的代码,还是写的不够快
    

    虚树:

    struct P{
    	ll to,next,v;
    }e[M],e2[M];
    
    ll cnt,head[N],dfn[N],idf[N],top[N],Minn[N],dep[N],fa[N],siz[N],son[N];
    ll dcnt;
    ll cnt2,head2[N],DP[N];
    
    void add(ll x,ll y,ll v){
    	e[++cnt].to = y;
    	e[cnt].v = v;
    	e[cnt].next = head[x];
    	head[x] = cnt;
    }
    
    void add2(ll x,ll y){
    	e2[++cnt2].to = y;
    	e2[cnt2].next = head2[x];
    	head2[x] = cnt2;
    }
    
    void dfs1(ll now,ll f){
    	fa[now] = f;
    	dep[now] = dep[f] + 1;
    	siz[now] = 1; 
    	for(int i = head[now];i;i = e[i].next){
    		ll v = e[i].to;
    		if(v != f){
    		Minn[v] = std::min(Minn[now],e[i].v);
    		dfs1(v,now);
    		siz[now] += siz[v];
    		if(siz[v] > siz[son[now]])
    		son[now] = v;
    		}
    	}
    }
    
    void dfs2(ll now,ll t){
    	top[now] = t;
    	dfn[now] = ++dcnt;
    	idf[dfn[now]] = now;
    	if(!son[now])
    	return;
    	dfs2(son[now],t);
    	for(int i = head[now];i;i = e[i].next){
    		ll v = e[i].to;
    		if(v == fa[now] || v == son[now])
    		continue;
    		dfs2(v,v);
    	}
    }
    
    ll lca(ll x,ll y){
    	while(top[x] != top[y]){
    		if(dep[top[x]] < dep[top[y]])
    		std::swap(x,y);
    		x = fa[top[x]];
    	}
    	if(dep[x] > dep[y])
    	std::swap(x,y);
    	return x;
    }
    
    ll stack[N];
    
    void build(){
    	cnt2 = 0;
    	std::sort(stack + 1,stack + stack[0] + 1);
    	ll s = stack[0];
    	for(int i = 2;i <= s;++i)
    	stack[++stack[0]] = dfn[lca(idf[stack[i]],idf[stack[i - 1]])];
    	std::sort(stack + 1,stack + stack[0] + 1);
    	s = std::unique(stack + 1,stack + stack[0] + 1) - stack - 1;
    	for(int i = 2;i <= s;++i)
    	add2(lca(idf[stack[i]],idf[stack[i - 1]]),idf[stack[i]]);
    }
    
    bool qr[N];
    
    void dfs(ll now){
    	ll s = 0;
    	DP[now] = Minn[now];
    	for(int i = head2[now];i;i = e2[i].next){
    		ll v = e2[i].to;
    		dfs(v);
    		s += DP[v];
    	}
    	if(s && !qr[now])
    	DP[now] = std::min(s,DP[now]);
    	else
    	qr[now] = 0;
    	head2[now] = 0;
    }
    

    淀粉质:

    struct P{
    	int to,next,v;
    }e[M];
    
    int cnt,head[N],dis[N],siz[N],dp[N],rev[N];
    bool vis[N];
    
    void add(int x,int y,int v){
    	e[++cnt].to = y;
    	e[cnt].next = head[x];
    	e[cnt].v = v;
    	head[x] = cnt;
    }
    
    ll n,k,rt,sum;
    
    void getrt(ll u,ll fa){
    	siz[u] = 1,dp[u] = 0;
    	for(int i = head[u];i;i = e[i].next){
    		ll v = e[i].to;
    		if(v == fa || vis[v])
    		continue;
    		getrt(v,u);
    		siz[u] += siz[v];
    		dp[u] = std::max(dp[u],siz[v]);
    	}
    	dp[u] = std::max((ll)dp[u],sum - siz[u]);
    	if(dp[u] < dp[rt])
    	rt = u;
    }
    
    ll ans = 0;
    ll tot = 0;
    
    void getdis(ll u,ll fa){
    	rev[++tot] = dis[u];
    	for(int i = head[u];i;i = e[i].next){
    		ll v = e[i].to;
    		if(v == fa || vis[v])
    		continue;
    		dis[v] = dis[u] + e[i].v;
    		getdis(v,u);
    	}
    }
    
    ll doit(ll u,ll s){
    	tot = 0,dis[u] = s,getdis(u,0);
    	std::sort(rev + 1,rev + tot + 1);
    	ll l = 1,r = tot;
    	ll ans = 0;
    	while(l <= r)
    	if(rev[l] + rev[r] <= k)
    	ans += r - l,++l;
    	else
    	--r;
    	return ans;
    }
    
    void solve(ll u){
    	vis[u] = 1,ans += doit(u,0);
    	for(int i = head[u];i;i = e[i].next){
    		ll v = e[i].to;
    		if(vis[v])continue;
    		ans -= doit(v,e[i].v);
    		sum = siz[v],dp[0] = n,rt = 0;
    		getrt(v,u),solve(rt);
    	}
    }
    

    树上启发式合并

    struct P{
    	ll to,next;
    }e[M];
    
    int cnt,C[N],head[N],c[N],siz[N],gson[N];
    ll ans[N],fans[N];
    
    void add(int x,int y){
    	e[++cnt].to = y;
    	e[cnt].next = head[x];
    	head[x] = cnt;
    }
    
    ll n;
    
    void dfs(int u,int fa){
    	siz[u] = 1;
    	for(int i = head[u];i;i = e[i].next){
    		int v = e[i].to;
    		if(v == fa)
    		continue;
    		dfs(v,u);
    		siz[u] += siz[v];
    		if(siz[v] > siz[gson[u]])
    		gson[u] = v;
    	}
    }
    
    std::queue<int>QWQ;
    
    ll maxx;
    
    void clear(){
    	maxx = 0;
    	while(!QWQ.empty()){
    		C[QWQ.front()] = 0;
    		QWQ.pop();
    	}
    }
    
    ll t;
    
    void init(int u,int fa){
    	QWQ.push(c[u]);
    	C[c[u]] ++ ;
    	if(C[c[u]] > maxx)
    	fans[t] = c[u],maxx = C[c[u]];
    	else
    	if(C[c[u]] == maxx)
    	fans[t] += c[u];
    	for(int i = head[u];i;i = e[i].next){
    		int v = e[i].to;
    		if(v == fa || v == gson[t])
    		continue;
    		init(v,u);
    	}
    }
    
    void solve(int u,int fa){
    	for(int i = head[u];i;i = e[i].next){
    		int v = e[i].to;
    		if(v == fa || v == gson[u])
    		continue;
    		solve(v,u);
    		clear();
    	}
    	if(gson[u])
    	solve(gson[u],u);
    	t = u;
    	fans[u] = fans[gson[u]];
    	init(u,fa);
    }
    
  • 相关阅读:
    BZOJ1001 狼抓兔子 终于过了!
    BZOJ 1901: Zju2112 Dynamic Rankings( 树状数组套主席树 )
    BZOJ 2302: [HAOI2011]Problem c( dp )
    BZOJ 1407: [Noi2002]Savage( 数论 )
    BZOJ 2661: [BeiJing wc2012]连连看( 费用流 )
    BZOJ 1021: [SHOI2008]Debt 循环的债务( dp )
    BZOJ 3170: [Tjoi 2013]松鼠聚会( sort )
    BZOJ 2301: [HAOI2011]Problem b( 数论 )
    BZOJ 2434: [Noi2011]阿狸的打字机( AC自动机 + DFS序 + 树状数组 )
    BZOJ 3231: [Sdoi2008]递归数列( 矩阵快速幂 )
  • 原文地址:https://www.cnblogs.com/dixiao/p/14629784.html
Copyright © 2011-2022 走看看