板子集

卡常火车头

学长(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) << "\n"; 
	}
	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 << "\n";
}
//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) << "\n";
}
//---------------------------------
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怎么办呢?有\0吗?不,\0在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("\n");
        ///开始遍历大串找其中的小串
        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\n",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('\n'), 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]\n",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]\n",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\n",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\n",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\n",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",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\n",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\n",u,v,k);
            }
        }
        return 0;
    }
posted @ 2020-07-07 21:43  hulne  阅读(193)  评论(3编辑  收藏  举报