zoukankan      html  css  js  c++  java
  • 板子集

    卡常火车头

    学长(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;
        }
    
    而我们终其一生,都希望能成为更好的人。
  • 相关阅读:
    Unique Binary Search Trees 解答
    Unique Paths II 解答
    Unique Paths 解答
    Maximum Subarray 解答
    Climbing Stairs 解答
    House Robber II 解答
    House Robber 解答
    Valid Palindrome 解答
    Container With Most Water 解答
    Remove Duplicates from Sorted List II 解答
  • 原文地址:https://www.cnblogs.com/moziii/p/13263466.html
Copyright © 2011-2022 走看看