• 板子集


    卡常火车头

    学长(wljss)那搬来的hhh

    #pragma GCC diagnostic error "-std=c++11"
    #pragma GCC target("avx")
    #pragma GCC optimize(3)
    #pragma GCC optimize("Ofast")
    #pragma GCC optimize("inline")
    #pragma GCC optimize("-fgcse")
    #pragma GCC optimize("-fgcse-lm")
    #pragma GCC optimize("-fipa-sra")
    #pragma GCC optimize("-ftree-pre")
    #pragma GCC optimize("-ftree-vrp")
    #pragma GCC optimize("-fpeephole2")
    #pragma GCC optimize("-ffast-math")
    #pragma GCC optimize("-fsched-spec")
    #pragma GCC optimize("unroll-loops")
    #pragma GCC optimize("-falign-jumps")
    #pragma GCC optimize("-falign-loops")
    #pragma GCC optimize("-falign-labels")
    #pragma GCC optimize("-fdevirtualize")
    #pragma GCC optimize("-fcaller-saves")
    #pragma GCC optimize("-fcrossjumping")
    #pragma GCC optimize("-fthread-jumps")
    #pragma GCC optimize("-funroll-loops")
    #pragma GCC optimize("-fwhole-program")
    #pragma GCC optimize("-freorder-blocks")
    #pragma GCC optimize("-fschedule-insns")
    #pragma GCC optimize("inline-functions")
    #pragma GCC optimize("-ftree-tail-merge")
    #pragma GCC optimize("-fschedule-insns2")
    #pragma GCC optimize("-fstrict-aliasing")
    #pragma GCC optimize("-fstrict-overflow")
    #pragma GCC optimize("-falign-functions")
    #pragma GCC optimize("-fcse-skip-blocks")
    #pragma GCC optimize("-fcse-follow-jumps")
    #pragma GCC optimize("-fsched-interblock")
    #pragma GCC optimize("-fpartial-inlining")
    #pragma GCC optimize("no-stack-protector")
    #pragma GCC optimize("-freorder-functions")
    #pragma GCC optimize("-findirect-inlining")
    #pragma GCC optimize("-fhoist-adjacent-loads")
    #pragma GCC optimize("-frerun-cse-after-loop")
    #pragma GCC optimize("inline-small-functions")
    #pragma GCC optimize("-finline-small-functions")
    #pragma GCC optimize("-ftree-switch-conversion")
    #pragma GCC optimize("-foptimize-sibling-calls")
    #pragma GCC optimize("-fexpensive-optimizations")
    #pragma GCC optimize("-funsafe-loop-optimizations")
    #pragma GCC optimize("inline-functions-called-once")
    #pragma GCC optimize("-fdelete-null-pointer-checks")
    

    线段树2

    #include<bits/stdc++.h>
    #define _ 0
    #define N 100001
    #define mid ((l + r) >> 1)
    #define pl (p << 1)
    #define pr (p << 1) | 1
    using namespace std;
    typedef long long ll;
    ll tr[N * 5], ta[N * 5], la[N * 5], o[N], mod;
    
    void up(int p){ tr[p] = tr[pl] + tr[pr]; }
    
    void down(int l, int r, int p){
    	if(la[p] != 1){
    		la[pl] = la[pl] * la[p] % mod; la[pr] = la[pr] * la[p] % mod;
    		ta[pl] = ta[pl] * la[p] % mod; ta[pr] = ta[pr] * la[p] % mod;
    		tr[pl] = tr[pl] * la[p] % mod; tr[pr] = tr[pr] * la[p] % mod;
    		la[p] = 1;
    	}
    	if(ta[p]){
    		ta[pl] = (ta[pl] + ta[p]) % mod; ta[pr] = (ta[pr] + ta[p]) % mod;
    		tr[pl] = (tr[pl] + (mid - l + 1) * ta[p]) % mod;
    		tr[pr] = (tr[pr] + (r - mid) * ta[p]) % mod;
    		ta[p] = 0;
    	}
    }
    
    void mul(int s, int t, int l, int r, ll c, int p){
    	if(s <= l and t >= r) {
    		la[p] = la[p] * c % mod; ta[p] = ta[p] * c % mod;
    		tr[p] = tr[p] * c % mod; return;
    	}down(l, r, p);
    	if(mid >= s) mul(s, t, l, mid, c, pl);
    	if(mid < t) mul(s, t, mid + 1, r, c, pr);
    	up(p);
    }
    
    void add(int s, int t, int l, int r, ll c, int p){
    	if(s <= l and t >= r) {          
    		ta[p] = (ta[p] + c) % mod;
    		tr[p] = (tr[p] + c * (r - l + 1)) % mod;
    		return;
    	}down(l, r, p);
    	if(mid >= s) add(s, t, l, mid, c, pl);
    	if(mid < t) add(s, t, mid + 1, r, c, pr);
    	up(p);
    }
    
    ll query(int s, int t, int l, int r, int p){
    	ll sum = 0;
    	if(s <= l and t >= r) return tr[p];
    	down(l, r, p);
    	if(mid >= s) sum = (sum + query(s, t, l, mid, pl)) % mod;
    	if(mid < t) sum = (sum + query(s, t, mid + 1, r, pr)) % mod;
    	return sum;
    }
    
    void construct(int l, int r, int p){
    	la[p] = 1;
    	if(l == r) { tr[p] = o[l]; return; }
    	construct(l, mid, pl); construct(mid + 1, r, pr); up(p);
    }
    
    int main(){
    	int n, m, op, x, y; ll k;  
    	cin >> n >> m >> mod;
    	for(int i = 1; i <= n; i ++) cin >> o[i];
    	construct(1, n, 1);
    	for(int i = 1; i <= m; i ++){
    		cin >> op >> x >> y;
    		if(op == 1){ cin >> k; mul(x, y, 1, n, k, 1); } 
    		if(op == 2){ cin >> k; add(x, y, 1, n, k, 1); }
    		if(op == 3) cout << query(x, y, 1, n, 1) << "
    "; 
    	}
    	return ~~(0^_^0);
    }
    

    枚举子集(二进制

    int S = 2333;
    for(int i = S; i; i = (i - 1) & S)
        cout << bitset<10>(i) << endl;
    

    快读快写模板

    inline void read(int &x){
    	x=0;register char c=getchar();
    	while(c<'0'||c>'9'){c=getchar();}
    	while(c>='0'&&c<='9'){x=(x<<3)+(x<<1)+(c^48);c=getchar();}
    }
    
    inline void write(int x){
         if(x < 0) putchar('-'),x = -x;
         if(x > 9) write(x / 10);
         putchar(x % 10 + '0');
    }
    

    快速幂&慢速乘

    ll msc(ll a, ll b, ll p){
        ll res = 0;
        while(b){
            if(b & 1) res = (res + a) % p;
            a = (a + a) % p;
            b = b >> 1;
        }
        return res;
    }
    
    ll ksm(ll a, ll b, ll p){
        a %= p;
        ll res = 1;
        while(b > 0){
            if(b & 1) res = res * a % p;
            a = a * a % p;
            b >>= 1;
        }
        return res;
    }
    

    树剖

    opt 1:x y z 表示 x 到 y 所有节点权值加 z

    opt 2:x y 表示求 x 到 y 所有节点的权值之和

    opt 3:x z 表示以 x 为根节点的子树内所有节点权值加 z

    opt 4:x 表示求以 x 为根节点的子树内所有节点权值之和

    #include <bits/stdc++.h>
    #define N 500010
    #define il inline
    using namespace std;
    typedef long long ll;
    il int in() {
        int x = 0, f = 1; char C = getchar();
        while(C < '0' or C > '9') { if(C == '-') f = -1; C = getchar(); }
        while(C >= '0' and C <= '9') { x = (x << 3) + (x << 1) + (C ^ 48); C = getchar();}
        return x * f;
    }
    int f[N], dep[N], sz[N], son[N], dfn[N], top[N], cnt[N], id[N], tot;
    //cnt:该子树最大节点编号(线段树上)dfn映射原标号与新标号
    int n, m, root, val[N], mod; //val:节点权值
    int e_cnt, to[N << 1], mrk[N << 1], head[N];
    struct hh { ll c, f; } t[N << 2]; //c:区间和 f:懒标记
    il void add(int x, int y) {
        to[++ e_cnt] = y, mrk[e_cnt] = head[x], head[x] = e_cnt;
    }
    //---------------------------------
    //找重儿子
    void dfs1(int u) {
        sz[u] = 1;
        for(int i = head[u]; i; i = mrk[i]) {
            int v = to[i];
            if(v == f[u]) continue;
            f[v] = u;
            dep[v] = dep[u] + 1;
            dfs1(v);
            sz[u] += sz[v];
            if(sz[v] > sz[son[u]]) son[u] = v;
        }
    }
    //找链头
    void dfs2(int u, int tp) {
        top[u] = tp;
        dfn[u] = ++ tot;
        id[tot] = u;
        if(son[u]) dfs2(son[u], tp);
        for(int i = head[u]; i; i = mrk[i]) {
            int v = to[i];
            if(v != son[u] and v != f[u]) dfs2(v, v);
        }
        cnt[u] = tot;
    }
    //----------------------------------
    //线段树
    #define mid ((l + r) >> 1)
    #define pl p << 1
    #define pr p << 1 | 1
    il void up(int p) { t[p].c = t[pl].c + t[pr].c; }
    
    void build(int l, int r, int p) {
        if(l == r) { t[p].c = val[id[l]]; return; } //线段树上用的是新编号
        build(l, mid, pl), build(mid + 1, r, pr);
        up(p);
    }
    
    il void down(int l, int r, int p) {
    	t[pl].f += t[p].f, t[pr].f += t[p].f;
        t[pl].c += (mid - l + 1) * t[p].f;
        t[pr].c += (r - mid) * t[p].f;
        t[p].f = 0;
    }
    
    void change(int x, int y, int l, int r, int p, ll c) {
        if(x <= l and r <= y) {
            t[p].c += (r - l + 1) * c;
            t[p].f += c;
            return;
        }
        if(t[p].f) down(l, r, p);
        if(mid >= x) change(x, y, l, mid, pl, c);
        if(mid < y) change(x, y, mid + 1, r, pr, c);
        up(p);
    }
    
    ll query(int x, int y, int l, int r, int p) {
        if(x <= l and r <= y) return t[p].c;
        if(t[p].f) down(l, r, p);
        ll ans = 0;
        if(mid >= x) ans += query(x, y, l, mid, pl), ans %= mod;
        if(mid < y) ans += query(x, y, mid + 1, r, pr), ans %= mod;
        return ans;
    }
    //-----------------------------------
    //opt1
    il void xy() {
    	int x = in(), y = in(), z = in();
        while(top[x] != top[y]) {
            if(dep[top[x]] > dep[top[y]]) swap(x, y);
            change(dfn[top[y]], dfn[y], 1, tot, 1, (ll)z);
            y = f[top[y]];
        }
        if(dep[x] > dep[y]) swap(x, y);
        change(dfn[x], dfn[y], 1, tot, 1, (ll)z);
    }
    //opt2
    il void xxyy() {
        int x = in(), y = in();
    	ll ans = 0;
        while(top[x] != top[y]) {
            if(dep[top[x]] > dep[top[y]]) swap(x, y);
            ans = (ans + query(dfn[top[y]], dfn[y], 1, tot, 1)) % mod;
            y = f[top[y]];
        }
        if(dep[x] > dep[y]) swap(x, y);
        ans = (ans + query(dfn[x], dfn[y], 1, tot, 1)) % mod;
        cout << ans << "
    ";
    }
    //opt3
    il void cx() {
        int x = in(), y = in();
        change(dfn[x], cnt[x], 1, tot, 1, (ll)y);
    }
    //opt4
    il void cxx() {
        int x = in();
        cout << query(dfn[x], cnt[x], 1, tot, 1) << "
    ";
    }
    //---------------------------------
    int main() {
        n = in(), m = in(), root = in(), mod = in();
        for(int i = 1; i <= n; i ++) val[i] = in();
        for(int i = 1, x, y; i < n; i ++) {
            x = in(), y = in();
            add(x, y), add(y, x);
        }
        dfs1(root);
        dfs2(root, root);
        build(1, tot, 1);
        for(int i = 1, op; i <= m; i ++) {
            op = in();
            if(op == 1) xy();
            else if(op == 2) xxyy();
            else if(op == 3) cx();
            else cxx();
        }
        return 0;
    }
    

    Manacher

    精简版

    const int maxn=1000010;
    char str[maxn];//原字符串
    char tmp[maxn<<1];//转换后的字符串
    int Len[maxn<<1];
    //转换原始串
    int INIT(char *st)
    {
        int i,len=strlen(st);
        tmp[0]='@';///开头加一个不等于#也不等于字符串的字符,这样就不用判断左边越界了,那么右边万一比到n+1怎么办呢?有吗?不,在n处,解决办法看16行
        for(i=1;i<=2*len;i+=2)
        {
            tmp[i]='#';
            tmp[i+1]=st[i/2];
        }
        tmp[2*len+1]='#';
        tmp[2*len+2]='$';///结尾搞一个不是@也不是#的字符
        tmp[2*len+3]=0;
        return 2*len+1;//返回转换字符串的长度
    }
    //Manacher算法计算过程
    int MANACHER(char *st,int len)
    {
         int mx=0,ans=0,po=0;//mx即为当前计算回文串最右边字符的最大值
         for(int i=1;i<=len;i++)
         {
             if(mx>i)
             Len[i]=min(mx-i,Len[2*po-i]);//在Len[j]和mx-i中取个小
             else
             Len[i]=1;//如果i>=mx,要从头开始匹配
             while(st[i-Len[i]]==st[i+Len[i]])
             Len[i]++;
             if(Len[i]+i>mx)//若新计算的回文串右端点位置大于mx,要更新po和mx的值
             {
                 mx=Len[i]+i;
                 po=i;
             }
             ans=max(ans,Len[i]);
         }
         return ans-1;//返回Len[i]中的最大值-1即为原串的最长回文子串额长度
    }
    

    KMP

        #include<bits/stdc++.h>
        const int N = 1e6+5;
        using namespace std;
        int nt[N];
        char s[N];
        char ss[N];
        int KMP() { ///求大串中有几个子串
            int len=strlen(s);
            int t=strlen(ss);
            nt[0]=-1;
            int cnt=0;
            ///构造next数组
            for (int i=0,j=-1; i<t; ){
                if (j==-1 || ss[i]==ss[j]) i++, j++, nt[i]=j;
                else j=nt[j];
            }
            for (int i=0;i<t;i++) printf("nt[%d]=%d ",i,nt[i]); printf("
    ");
            ///开始遍历大串找其中的小串
            for (int i=0,j=0; i<len; ){
                if (j==-1 || ss[j]==s[i]) i ++, j ++;
                else j=nt[j];
                if (j==t){
                    cnt++;
                    j=0;
                }
            }
            return cnt;
        }
         
        int main() {
            while (cin>>s) {
                cin>>ss;
                cout<<KMP()<<endl;
            }
        }
    

    邻接表存字典树

    #include<cstdio>
    #include<cstring>
    #define ll long long
    using namespace std;
    const int N = 4000*1001 + 5;
    struct node {
        int son, right, sum;
        char ch;
    }trie[N];
    int id; ll ans;
    void init() {
        ans = 0; id = 1;
        trie[0].right = trie[0].son = trie[0].sum = 0;
    }
    void insert(char *s) {
        int u = 0,j;
        int len = strlen(s);
        for (int i=0;i<=len;i++){
            bool flag = false;
            for (j=trie[u].son;j!=0;j=trie[j].right)
                if (s[i]==trie[j].ch) { flag = true; break; }
            if (!flag){
                j = id++;
                trie[j].right = trie[u].son;
                trie[u].son = j;
                trie[j].ch = s[i];
                trie[j].son = trie[j].sum = 0;
            }
            ans += (trie[u].sum+trie[j].sum);
            if (i==len) trie[j].sum++;
            trie[u].sum++;
            u = j;
        }
    }
    int main() {
        int n; char in[1010];
        for(int kca = 1; scanf("%d", &n), n; kca ++) {
            init();
            while (n--) scanf("%s",in),insert(in);
            printf("Case %d: %lld
    ",kca,ans);
        }
    }
    

    矩阵快速幂

    #include<bits/stdc++.h>
    #define mod 1000000007
    #define N 102
    #define ll long long
    using namespace std;
    int n;
    
    struct hh{
    	ll a[N][N];
    	hh(){ memset(a, 0, sizeof(a)); }
    	inline void build(){
    		for(int i = 1; i <= n; i ++) 
    		  a[i][i] = 1;
    	}
    } a;
    
    hh operator *(const hh &x, const hh & y){
    	hh z;
    	for(int s = 1; s <= n; s ++)
    	  for(int i = 1; i <= n; i ++)
    	    for(int j = 1; j <= n; j ++)
    	      z.a[i][j] = (z.a[i][j] + x.a[i][s] * y.a[s][j] % mod) % mod;	
    	return z;
    }
    ll k;
    int main(){
    	cin >> n >> k;
    	hh ans; ans.build();
    	for(int i = 1; i <= n; i ++)
    	  for(int j = 1; j <= n; j ++)
    	    cin >> a.a[i][j];
    	while(k){
    		if(k & 1) ans = ans * a;
    		a = a * a;
    		k >>= 1;
    	} 
    	for(int i = 1; i <= n; putchar('
    '), i ++)
    	  for(int j = 1; j <= n; j ++)
    	    cout << ans.a[i][j] << " ";
    	return 0;
    }
    

    堆优化dijkstra 算法

        const int N = 1e5+5;///点的数量
        const int M = 5e5+5;///边的数量
         
        struct Edge { int to, last, w; }edge[M];
        int head[N],id;
         
        void add(int u,int v,int w) {//建从u->v,权值为w的边
            edge[id].to = v;
            edge[id].w = w;
            edge[id].last = head[u];
            head[u] = id++;
        }
        void init() {//建边前的初始化
            memset(head,0,sizeof head);
            id = 1;
        }
        struct node {//储存点
            int now;
            int w;//到达now节点的这条边的权值
            bool operator < (const node& a)const{//***比较方式要和自己想的反过来***
                return w>a.w;
            }
        };
        bool vis[N];//是否求出最短路径
        void dijkstra() {
            memset(vis,0,sizeof vis);
            priority_queue<node>que;
            int root = 1;//单元最短路径的源点
            que.push({root,0});
            while (!que.empty()){
                node now = que.top();que.pop();
                if (vis[now.now]) continue;
                vis[now.now] = true;
                /*
                当前点now记录了这个点到源点的最短距离,问题可以在这儿处理
                */
                for (int i=head[now.now];i!=0;i=edge[i].last){
                    que.push({edge[i].to,edge[i].w+now.w});//***权值记得要加now.w***
                }
            }
        }
    

    SPFA

        const int N = 1e4+5;
        const int M = 5e4+5;     
        struct Edge { int to,last,w; }edge[M];
        int id,head[N]; 
        void add(int u,int v,int w) {
            edge[id].to = v; edge[id].w = w; edge[id].last = head[u]; head[u] = id++;
        }
        void init() { id = 1; memset(head,0,sizeof head); }
        int val[N];//记录该节点被更新多少次
        int dis[N];//记录单源最短路
         
        void SPFA(int V) { //V表示节点数 
            memset(dis,INF,sizeof dis);
            memset(val,0,sizeof val); 
            int root = 1;//若只用于判负环,源点可以随便取
            bool flag = false;//是否有负环,初始化为无
            dis[root] = 0;
            /* 下面注释掉的四行是SPFA的优化,节点数多的时候一般来说是会优化...
            就是先让dis[]小的去松弛,这样可以让进队列的数更少 */
            //deque<int>que;
            //que.pb(root);
            queue<int>que;
            que.push(root); 
            while (!que.empty()){
                int now = que.front();que.pop_front();
                int v;
                for (int i=head[now];i!=0;i=edge[i].last){
                    v = edge[i].to;
                    if (dis[v]>dis[now]+edge[i].w){
                        dis[v] = dis[now] + edge[i].w;
                        //que.pb(v);
                        //if (dis[que.front()]<dis[que.back()]){que.pf(v);que.pop_back();}
                        que.push(v);
                        val[v]++;
                        if (val[v]==V) {flag = true;break;}
                    }
                }
                if (flag) break;
            }
        }
    

    动态开点线段树

    求逆序

        #include<bits/stdc++.h> 
        using namespace std; 
        #define for1(i,a,b) for (int i=a;i<=b;i++)
        #define for0(i,a,b) for (int i=a;i<b;i++)
        #define ll long long
        #define mid int m = l+r>>1
        #define tl tree[rt].l
        #define tr tree[rt].r 
        const int N = 5e5+5, maxn = 500000*32 + 5, MAXR = 1e9; 
        struct node { int l,r; int sum; }tree[maxn]; int sz; 
        void init(){sz = 2;} 
        void push_up(int rt) { tree[rt].sum = tree[tl].sum + tree[tr].sum; } 
        void update(int p,int& rt,int l,int r) {
            //printf("update[%d,%d]
    ",l,r);
            if (!rt){ rt = sz++;  tl = tr = tree[rt].sum = 0; }
            if (l==r){  tree[rt].sum++; return; }
            mid; if (p<=m) update(p,tl,l,m);
            else update(p,tr,m+1,r);
            push_up(rt);
        } 
        ll query(int L,int R,int rt,int l,int r) {
            //printf("query[%d,%d]
    ",l,r);
            if (!rt) return 0;
            if (L<=l && r<=R) return tree[rt].sum;
            ll ans = 0; mid;
            if (L<=m) ans += query(L,R,tl,l,m);
            if (R>m) ans += query(L,R,tr,m+1,r);
            return ans;
        } 
        int main() {
            init(); int n; scanf("%d",&n);
            ll ans = 0; int root = 1;
            for1(i,1,n){
                int x; scanf("%d",&x);
                if (x+1<=MAXR) ans += query(x+1,MAXR,1,1,MAXR);//防止区间无效
                update(x,root,1,MAXR);
            } printf("%lld
    ",ans);
            return 0;
        }
    

    可持久化线段树(主席树)

    静态区间第k小

        int a[N], data[N];
        void discrete(int n) {//使用该函数把a[i]变成原本a[i]离散化后对应的数,data可以根据离散化后的值推实际的大小
            for1(i,1,n) data[i] = a[i];
            sort(data+1,data+1+n);
            int cnt = unique(data+1,data+1+n) - data;
            for1(i,1,n) a[i] = lower_bound(data+1,data+cnt,a[i]) - data;
        }
        struct node { int l, r, sum; }tree[M];
        int sz,root[N]; 
        void push_up(int rt){  tree[rt].sum = tree[tl].sum + tree[tr].sum; } 
        void update(int old,int p,int& rt,int l,int r) {
            rt = sz++;//这里容易脑抽写成if(!rt) rt = sz++
            if (l==r){ tree[rt].sum = tree[old].sum + 1; return ; }
            tree[rt] = tree[old]; mid;
            if (p<=m) update(tl,p,lson);
            else update(tr,p,rson);
            push_up(rt);
        } int ccnt;
        int query(int old,int k,int rt,int l,int r) {
            if (l==r) return data[l]; mid;
            ccnt = tree[tl].sum - tree[tree[old].l].sum;
            if (ccnt >= k) return query(tree[old].l,k,lson);
            else return query(tree[old].r,k-ccnt,rson);
        } 
        int main() {
            int n,m; scanf("%d %d",&n,&m);
            sz = 1;
            for1(i,1,n) scanf("%d",a+i);
            discrete(n);
            for1(i,1,n) update(root[i-1],a[i],root[i],1,n); 
            int l,r,k;
            for1(i,1,m){
                scanf("%d %d %d",&l,&r,&k);
                printf("%d
    ",query(root[l-1],k,root[r],1,n));
            } 
            return 0;
        }
    

    随机生成一棵树 + 随机生成两个节点询问路径第k小(对拍用)

        //不保证一定没有问题
         
        #include<bits/stdc++.h>
         
        using namespace std;
         
        #define ll long long
        #define for1(i,a,b) for (int i=a;i<=b;i++)
        #define for0(i,a,b) for (int i=a;i<b;i++)
         
        const int maxINT = ((1LL<<31)-1);
        const int N = 1e5+5;
         
        int Rand(bool tag=false){//生成int范围随机数,tag=true表示允许负数
            int s1 = rand();
            int s2 = rand();
            int flag = 1;
            if (tag)flag = rand()%2==0? 1:-1;
            return 1LL*flag*s1*s2%maxINT;
        }
        //**************************************************************************
        //建树
        struct E{
            int to,last;
        }edge[N<<1];
        int head[N],id;
        void add(int u,int v){edge[id].to = v;edge[id].last = head[u];head[u] = id++;}
        //***********************************************************************************
        //并查集判断两个点是否在同一个集合中
        int uf[N];
        int find1(int x){
            int r = x;
            while (uf[r]!=r) r = uf[r];
            for (int i = x,j;i!=r;i=j){
                j = uf[i];
                uf[i] = r;
            }
            return r;
        }
        void join(int a,int b){
            a = find1(a),b = find1(b);
            if (a!=b) uf[a] = b;
        }
        //************************************************************************************
        int dep[N],lca[N][20];
        void dfs(int now,int f,int depth){
            lca[now][0] = f;
            dep[now] = depth;
            for (int i=head[now];i!=0;i=edge[i].last){
                int v = edge[i].to;
                if (v==f) continue; 
                dfs(v,now,depth+1);
            }
        }
         
        void getst(int n){
            for (int j=1;(1<<j)<=n;j++)
                for (int i=1;i<=n;i++)
                    lca[i][j] = lca[lca[i][j-1]][j-1];
        }
         
        int getlca(int x,int y){
            if (dep[x]<dep[y]) swap(x,y);
            int differ = dep[x]-dep[y];
            for (int i=0;(1<<i)<=differ;i++){
                if ((1<<i)&differ){
                    x = lca[x][i];
                }
            }
            if (x==y) return x;
            for (int i=18;i>=0;i--){
                if (lca[x][i]!=lca[y][i]) x = lca[x][i],y = lca[y][i];
            }
            return lca[x][0];
        }
        //**************************************************************************************
        int main()
        {
            srand(time(0));
            freopen("C:/Users/DELL/Desktop/input.txt", "w", stdout);//输入想要保存文件的路径
            /*u*/ //修改数据组数
            int T = 100;//数据组数,可修改
            printf("%d
    ",T);
            /*d*/
            /*u*/ //修改生成的树最多节点个数,必须<=1e5
            int maxsize = 20;
            /*d*/
            while(T--){
                /*u*/ //修改当前这组数据的节点数以及询问次数,q默认10次
                int n = Rand()%(maxsize+1),q=10;
                if (!n) n++;
                /*d*/
                printf("%d %d
    ",n,q);
         
                for1(i,1,n) uf[i] = i,head[i] = 0;
                memset(lca,0,sizeof lca);
                id = 1;
         
                for1(i,1,n){
                    if (i!=1) printf(" ");
                    printf("%d",Rand(true));
                }puts("");//生成每个节点的值
         
                int hulue = Rand()%(n+1);
                if (!hulue) hulue++;
                for1(i,1,n){
                    if (i==hulue) continue;
                    int v;
                    do {
                        v = Rand()%(n+1);
                        if (!v) v++;
                    }while (find1(i)==find1(v));
                    join(i,v);//并查集
                    printf("%d %d
    ",i,v);//生成数据
                    add(i,v);add(v,i);//生成树,用于check合法的k
                }//随机生成一棵树结束
         
                dfs(1,0,1);
                getst(n);
         
                while(q--){
                    int u = Rand()%(n+1),v = Rand()%(n+1);
                    if (!u) u++;if (!v) v++;
                    int LCA = getlca(u,v);
                    int maxk = dep[u]-dep[LCA]+dep[v]-dep[LCA]+1;
                    int k = Rand()%(maxk+1);
                    if (!k) k++;
                    printf("%d %d %d
    ",u,v,k);
                }
            }
            return 0;
        }
    
    而我们终其一生,都希望能成为更好的人。
  • 相关阅读:
    python基础之流程控制
    多线程---阻塞队列
    多线程---线程同步
    多线程---线程实现
    多线程start();之后会开辟新的栈空间
    java中使用String的split分隔字符串注意事项
    IO流
    java中的多态
    关于java中的接口
    关于final关键字
  • 原文地址:https://www.cnblogs.com/moziii/p/13263466.html
Copyright © 2020-2023  润新知