while true; do ./data_maker>tmp.in #出数据 ./MyProg<tmp.in>tmp.out #被测程序 ./StdProg<tmp.in>tmp2.out #正确(暴力)程序 if diff tmp.out tmp2.out; then #比较两个输出文件 printf "AC\n" #结果相同显示AC elif diff -B -b tmp.out tmp2.out; then printf "PE\n" else printf "WA\n" #结果不同显示WA,并退出 exit 0 fi done
///n rows m columns using namespace std; const int maxnode = 100010; const int MaxM = 1010; const int MaxN = 1010; struct DLX { int n,m,size; int U[maxnode],D[maxnode],R[maxnode],L[maxnode],Row[maxnode],Col[maxnode]; int H[MaxN], S[MaxM]; int ansd, ans[MaxN]; void init(int _n,int _m) { n = _n; m = _m; for(int i = 0; i <= m; i++) { S[i] = 0; U[i] = D[i] = i; L[i] = i-1; R[i] = i+1; } R[m] = 0; L[0] = m; size = m; for(int i = 1; i <= n; i++) H[i] = -1; } void Link(int r,int c) { ++S[Col[++size]=c]; Row[size] = r; D[size] = D[c]; U[D[c]] = size; U[size] = c; D[c] = size; if(H[r] < 0)H[r] = L[size] = R[size] = size; else { R[size] = R[H[r]]; L[R[H[r]]] = size; L[size] = H[r]; R[H[r]] = size; } } void remove(int c) { L[R[c]] = L[c]; R[L[c]] = R[c]; for(int i = D[c]; i != c; i = D[i]) for(int j = R[i]; j != i; j = R[j]) { U[D[j]] = U[j]; D[U[j]] = D[j]; --S[Col[j]]; } } void resume(int c) { for(int i = U[c]; i != c; i = U[i]) for(int j = L[i]; j != i; j = L[j]) ++S[Col[U[D[j]]=D[U[j]]=j]]; L[R[c]] = R[L[c]] = c; } //d为递归深度 bool Dance(int d) { if(R[0] == 0) { ansd = d; return true; } int c = R[0]; for(int i = R[0]; i != 0; i = R[i]) if(S[i] < S[c]) c = i; remove(c); for(int i = D[c]; i != c; i = D[i]) { ans[d] = Row[i]; for(int j = R[i]; j != i; j = R[j])remove(Col[j]); if(Dance(d+1))return true; for(int j = L[i]; j != i; j = L[j])resume(Col[j]); } resume(c); return false; } };
///n row m col, ansd(INF) using namespace std; const int MaxM = 15*15+10; const int MaxN = 15*15+10; const int maxnode = MaxN * MaxM; const int INF = 0x3f3f3f3f; struct DLX { int n,m,size; int U[maxnode],D[maxnode],R[maxnode],L[maxnode],Row[maxnode],Col[maxnode]; int H[MaxN],S[MaxM]; int ansd; void init(int _n,int _m) { n = _n; m = _m; for(int i = 0; i <= m; i++) { S[i] = 0; U[i] = D[i] = i; L[i] = i-1; R[i] = i+1; } R[m] = 0; L[0] = m; size = m; for(int i = 1; i <= n; i++)H[i] = -1; } void Link(int r,int c) { ++S[Col[++size]=c]; Row[size] = r; D[size] = D[c]; U[D[c]] = size; U[size] = c; D[c] = size; if(H[r] < 0)H[r] = L[size] = R[size] = size; else { R[size] = R[H[r]]; L[R[H[r]]] = size; L[size] = H[r]; R[H[r]] = size; } } void remove(int c) { for(int i = D[c]; i != c; i = D[i]) L[R[i]] = L[i], R[L[i]] = R[i]; } void resume(int c) { for(int i = U[c]; i != c; i = U[i]) L[R[i]] = R[L[i]] = i; } bool v[MaxM]; int f() { int ret = 0; for(int c = R[0]; c != 0; c = R[c])v[c] = true; for(int c = R[0]; c != 0; c = R[c]) if(v[c]) { ret++; v[c] = false; for(int i = D[c]; i != c; i = D[i]) for(int j = R[i]; j != i; j = R[j]) v[Col[j]] = false; } return ret; } void Dance(int d) { if(d + f() >= ansd)return; if(R[0] == 0) { if(d < ansd)ansd = d; return; } int c = R[0]; for(int i = R[0]; i != 0; i = R[i]) if(S[i] < S[c]) c = i; for(int i = D[c]; i != c; i = D[i]) { remove(i); for(int j = R[i]; j != i; j = R[j])remove(j); Dance(d+1); for(int j = L[i]; j != i; j = L[j])resume(j); resume(i); } } };
typedef unsigned long long ULL; const int SIZE = 100003; const int SEED = 13331; const int MAX_N = 50000 + 10; char s[MAX_N]; struct HASH{ ULL H[MAX_N]; ULL XL[MAX_N]; int len; HASH(){} void build(char *s){ len=strlen(s); H[len]=0; XL[0]=1; for (int i=len-1;i>=0;i--){ H[i]=H[i+1]*SEED+s[i]; XL[len-i]=XL[len-i-1]*SEED; } } ULL hash(int i,int L){ return H[i]-H[i+L]*XL[L]; } }hs;
int lcp(int i,int j){ int l=0,r=min(len-i,len-j); int res=0; while (l<=r){ int mid=(l+r)/2; if (hash(i,mid)==hash(j,mid)){ res=mid; l=mid+1; } else{ r=mid-1; } } return res; }
const int MAXN = 2000010; struct KMP { int f[MAXN]; void getFail(char S[]) { int i=0,j=-1; int len=strlen(S); f[0]=-1; while (i<len) { if (j==-1||S[i]==S[j]) { i++,j++; f[i]=j; } else j=f[j]; } } ///Whether S is a substring of T ///Or whether T has S; /** Use either is right**/ int beat(char T[],char S[]) { int i=0,j=0; int n=strlen(T); int m=strlen(S); getFail(S); while(i<n) { if(j==-1||T[i]==S[j]) i++,j++; else j=f[j]; if(j==m) return 1; } return 0; } int beat(char T[],char S[]) { int i=0,j=0; int n=strlen(T); int m=strlen(S); getFail(S); for(i=0; i<n; i++) { while(j!=-1&&T[i]!=S[j]) j=f[j]; j++; if(j==m) return 1; } return 0; } } soul;
const int MM=100005; int next[MM],extand[MM]; char S[MM],T[MM]; void GetNext(const char *T){ int len=strlen(T),a=0; next[0]=len; while(a<len-1 && T[a]==T[a+1]) a++; next[1]=a; a=1; for(int k=2;k<len;k++){ int p=a+next[a]-1,L=next[k-a]; if( (k-1)+L >= p){ int j = (p-k+1)>0 ? (p-k+1) : 0; while(k+j<len && T[k+j]==T[j]) j++; next[k]=j; a=k; } else next[k]=L; } } void GetExtand(const char *S,const char *T){ GetNext(T); int slen=strlen(S),tlen=strlen(T),a=0; int MinLen = slen < tlen ? slen : tlen; while(a<MinLen && S[a]==T[a]) a++; extand[0]=a; a=0; for(int k=1;k<slen;k++){ int p=a+extand[a]-1, L=next[k-a]; if( (k-1)+L >= p){ int j= (p-k+1) > 0 ? (p-k+1) : 0; while(k+j<slen && j<tlen && S[k+j]==T[j]) j++; extand[k]=j; a=k; } else extand[k]=L; } } int main(){ while(scanf("%s%s",S,T)==2){ GetExtand(S,T); for(int i=0;i<strlen(T);i++) printf("%d ",next[i]); puts(""); for(int i=0;i<strlen(S);i++) printf("%d ",extand[i]); puts(""); } return 0; }
const int NODE = 1e5+10,CH=26; int queue[NODE]; struct DFA { int ch[NODE][CH],f[NODE],val[NODE],last[NODE],sz; void init() { sz=1; memset(ch[0],0,sizeof(ch[0])); } void nn(int u,int c) { memset(ch[sz],0,sizeof(ch[sz])); val[sz]=0; ch[u][c]=sz++; } void ins(char *s) { int u=0; for(; *s; s++) { int c=idx(*s); if(!ch[u][c]) nn(u,c); u=ch[u][c]; } val[u]=1; } void getfail() { int *rear=queue,*front=queue; for(int c=0; c<CH; c++) { int u=ch[0][c]; if(u) f[u]=0,last[u]=0,*rear++=u; } while(rear!=front) { int cur = *front++; for(int c=0; c<CH; c++) { int u=ch[cur][c]; int fail=f[cur]; if(u) { while(fail && !ch[fail][c]) fail = f[fail]; f[u]=ch[fail][c]; last[u]=val[f[u]]?f[u]:last[f[u]]; *rear++=u; } } } } int calc(char *s) { int sum=0; int u=0; for(; *s; s++) { int c=idx(*s); while(u&&!ch[u][c]) u=f[u]; u=ch[u][c]; for(int tmp=u; tmp; tmp=last[tmp]) sum+=val[tmp]; } //puts(""); return sum; } int search(char *s) { int u=0; for(; *s; s++) { int c=idx(*s); if(!ch[u][c]) return 0; u=ch[u][c]; } return val[u]; } } soul;
const int maxn=3e5*2+10; /****************************************************************** ** 后缀数组 Suffix Array ** INIT:solver.call_fun(char* s); ** CALL: solver.lcp(int i,int j); //后缀i与后缀j的最长公共前缀 ** SP_USE: solver.LCS(char *s1,char* s2); //最长公共字串 ******************************************************************/ struct SuffixArray{ int r[maxn]; int sa[maxn],rank[maxn],height[maxn]; int t[maxn],t2[maxn],c[maxn],n; int m;//模板长度 void init(char* s){ n=strlen(s); for (int i=0;i<n;i++) r[i]=int(s[i]); m=300; } int cmp(int *r,int a,int b,int l){ return r[a]==r[b]&&r[a+l]==r[b+l]; } /** 字符要先转化为正整数 待排序的字符串放在r[]数组中,从r[0]到r[n-1],长度为n,且最大值小于m。 所有的r[i]都大于0,r[n]无意义算法中置0 函数结束后,结果放在sa[]数组中(名次从1..n),从sa[1]到sa[n]。s[0]无意义 **/ void build_sa(){ int i,k,p,*x=t,*y=t2; r[n++]=0; for (i=0;i<m;i++) c[i]=0; for (i=0;i<n;i++) c[x[i]=r[i]]++; for (i=1;i<m;i++) c[i]+=c[i-1]; for (i=n-1;i>=0;i--) sa[--c[x[i]]]=i; for (k=1,p=1;k<n;k*=2,m=p){ for (p=0,i=n-k;i<n;i++) y[p++]=i; for (i=0;i<n;i++) if (sa[i]>=k) y[p++]=sa[i]-k; for (i=0;i<m;i++) c[i]=0; for (i=0;i<n;i++) c[x[y[i]]]++; for (i=1;i<m;i++) c[i]+=c[i-1]; for (i=n-1;i>=0;i--) sa[--c[x[y[i]]]]=y[i]; swap(x,y); p=1; x[sa[0]]=0; for (i=1;i<n;i++) x[sa[i]]=cmp(y,sa[i-1],sa[i],k)?p-1:p++; } n--; } /** height[2..n]:height[i]保存的是lcp(sa[i],sa[i-1]) rank[0..n-1]:rank[i]保存的是原串中suffix[i]的名次 **/ void getHeight(){ int i,j,k=0; for (i=1;i<=n;i++) rank[sa[i]]=i; for (i=0;i<n;i++){ if (k) k--; j=sa[rank[i]-1]; while (r[i+k]==r[j+k]) k++; height[rank[i]]=k; } } int d[maxn][20]; //元素从1编号到n void RMQ_init(int A[],int n){ for (int i=1;i<=n;i++) d[i][0]=A[i]; for (int j=1;(1<<j)<=n;j++) for (int i=1;i+j-1<=n;i++) d[i][j]=min(d[i][j-1],d[i+(1<<(j-1))][j-1]); } int RMQ(int L,int R){ int k=0; while ((1<<(k+1))<=R-L+1) k++; return min(d[L][k],d[R-(1<<k)+1][k]); } void LCP_init(){ RMQ_init(height,n); } int lcp(int i,int j){ if (rank[i]>rank[j]) swap(i,j); return RMQ(rank[i]+1,rank[j]); } void call_fun(char* s){ init(s);//初始化后缀数组 build_sa();//构造后缀数组sa getHeight();//计算height与rank LCP_init();//初始化RMQ } int LCS(char* s1,char* s2){ int p,ans; int l=strlen(s1); p=l; s1[l]='$'; s1[l+1]='\0'; strcat(s1,s2); call_fun(s1); ans=0; for (int i=2;i<=n;i++) if ((sa[i-1]<p&&sa[i]>p)||(sa[i-1]>p&&sa[i]<p)) ans=max(ans,height[i]); return ans; } }solver;
#include <cstdio> #include <cstring> #include <algorithm> #include <iostream> #include <vector> #define sz(x) int(x.size()) using namespace std; typedef vector<int> VI; const int maxn = 250000+10; class SuffixAutomaton{ private: struct Node{ Node *suf, *go[26]; int val; Node(){ suf=NULL; val=0; memset(go,0,sizeof(go)); } void clear(){ suf=NULL; val=0; memset(go,0,sizeof(go)); } int calc(){ if (suf==0) return 0; return val-suf->val; } }; Node *root,*last; Node nodePool[maxn*2],*cur; Node* newNode(){ Node* res=cur++; res->clear(); return res; } int tot; void extend(int w){ Node *p=last; Node *np=newNode(); np->val=p->val+1; while (p&&!p->go[w]){ p->go[w]=np; p=p->suf; } if (!p){ np->suf=root; tot+=np->calc(); } else{ Node *q=p->go[w]; if (p->val+1==q->val){ np->suf=q; tot+=np->calc(); } else{ Node *nq=newNode(); memcpy(nq->go,q->go,sizeof(q->go)); tot-=p->calc()+q->calc(); nq->val=p->val+1; nq->suf=q->suf; q->suf=nq; np->suf=nq; tot+=p->calc()+q->calc()+np->calc()+nq->calc(); while (p&&p->go[w]==q){ p->go[w]=nq; p=p->suf; } } } last = np; } public: void init(){ cur=nodePool; root=newNode(); last=root; } VI getSubString(char s[]){ VI v; tot=0; int len=strlen(s); for (int i=0;i<len;i++){ extend(s[i]-'a'); v.push_back(tot); } return v; } int getLCS(char A[],char B[]){ int res=0,step=0; int lenA=strlen(A); int lenB=strlen(B); for (int i=0;i<lenA;i++) extend(A[i]-'a'); Node *p=root; for (int i=0;i<lenB;i++){ int x=B[i]-'a'; if (p->go[x]){ step++; p=p->go[x]; } else{ while (p&&!p->go[x]) p=p->suf; if (!p){ p=root; step=0; } else{ step=p->val+1; p=p->go[x]; } } res=max(res,step); } return res; } }atm;
#include <iostream> #include <cstring> #include <cstdio> using namespace std; typedef long long LL; const int maxn=300000; const int maxm=160000; /*************** SAM 真·模板 ***************/ struct State { State *par; State *go[52]; int val; // max,当前状态能接收的串的最长长度 int mi; // min,当前状态能接受的串的最短长度,即 par->val+1 int cnt; // 附加域,用来计数 int right; // right集,表示当前状态可以在多少个位置上出现 void init(int _val = 0){ par = 0; val = _val; cnt=0; mi=0; right=0; memset(go,0,sizeof(go)); } int calc(){ // 表示该状态能表示多少中不同的串 if (par==0) return 0; return val-par->val; } }; State *root, *last, *cur; State nodePool[maxn]; State* newState(int val = 0) { cur->init(val); return cur++; } //int total; // 不同的子串个数。 void initSAM() { //total = 0; cur = nodePool; root = newState(); last = root; } void extend(int w) { State* p = last; State* np = newState(p->val + 1); np->right=1; // 设置right集 while (p && p->go[w] == 0) { p->go[w] = np; p = p->par; } if (p == 0) { np->par = root; //total+=np->calc(); } else { State* q = p->go[w]; if (p->val + 1 == q->val) { np->par = q; //total+=np->calc(); } else { State* nq = newState(p->val + 1); memcpy(nq->go, q->go, sizeof(q->go)); //total -= q->calc(); nq->par = q->par; q->par = nq; np->par = nq; //total += q->calc()+nq->calc()+np->calc(); while (p && p->go[w] == q) { p->go[w] = nq; p = p->par; } } } last = np; } int d[maxm]; State* b[maxn]; void topo(){ // 求出parent树的拓扑序 int cnt=cur-nodePool; int maxVal=0; memset(d,0,sizeof(d)); for (int i=1;i<cnt;i++) maxVal=max(maxVal,nodePool[i].val),d[nodePool[i].val]++; for (int i=1;i<=maxVal;i++) d[i]+=d[i-1]; for (int i=1;i<cnt;i++) b[d[nodePool[i].val]--]=&nodePool[i]; b[0]=root; } void gaoSamInit(){ // 求出SAM的附加信息 State* p; int cnt=cur-nodePool; for (int i=cnt-1;i>0;i--){ p=b[i]; p->par->right+=p->right; p->mi=p->par->val+1; } } char s[maxm]; const int INF=0x3f3f3f3f; int gao(char s[]){ int ans=INF; int cnt=cur-nodePool; int len=strlen(s); int lcs=0; State* p=root; for (int i=0;i<len;i++){ int son=s[i]-'a'; if (p->go[son]!=0){ lcs++; p=p->go[son]; } else{ while (p&&p->go[son]==0) p=p->par; if (p==0){ lcs=0; p=root; } else{ lcs=p->val+1; p=p->go[son]; } } // TODO: if (lcs>0) p->cnt++; } for (int i=cnt-1;i>0;i--){ p=b[i]; // TODO: if (p->right==1&&p->cnt==1) ans=min(ans,p->mi); p->par->cnt += p->cnt; } return ans; }
后缀自动机的遍历。
给一个字符串S,每次可以将它的第一个字符移到最后面,求这样能得到的字典序最小的字符串。const int MAXN = 100005 ; const int N = 26 ; struct Palindromic_Tree { int next[MAXN][N] ;//next指针,next指针和字典树类似,指向的串为当前串两端加上同一个字符构成 int fail[MAXN] ;//fail指针,失配后跳转到fail指针指向的节点 int cnt[MAXN] ; int num[MAXN] ; int len[MAXN] ;//len[i]表示节点i表示的回文串的长度 int S[MAXN] ;//存放添加的字符 int last ;//指向上一个字符所在的节点,方便下一次add int n ;//字符数组指针 int p ;//节点指针 int newnode ( int l ) {//新建节点 for ( int i = 0 ; i < N ; ++ i ) next[p][i] = 0 ; cnt[p] = 0 ; num[p] = 0 ; len[p] = l ; return p ++ ; } void init () {//初始化 p = 0 ; newnode ( 0 ) ; newnode ( -1 ) ; last = 0 ; n = 0 ; S[n] = -1 ;//开头放一个字符集中没有的字符,减少特判 fail[0] = 1 ; } int get_fail ( int x ) {//和KMP一样,失配后找一个尽量最长的 while ( S[n - len[x] - 1] != S[n] ) x = fail[x] ; return x ; } void add ( int c ) { c -= 'a' ; S[++ n] = c ; int cur = get_fail ( last ) ;//通过上一个回文串找这个回文串的匹配位置 if ( !next[cur][c] ) {//如果这个回文串没有出现过,说明出现了一个新的本质不同的回文串 int now = newnode ( len[cur] + 2 ) ;//新建节点 fail[now] = next[get_fail ( fail[cur] )][c] ;//和AC自动机一样建立fail指针,以便失配后跳转 next[cur][c] = now ; num[now] = num[fail[now]] + 1 ; } last = next[cur][c] ; cnt[last] ++ ; } void count () { for ( int i = p - 1 ; i >= 0 ; -- i ) cnt[fail[i]] += cnt[i] ; //父亲累加儿子的cnt,因为如果fail[v]=u,则u一定是v的子回文串! } } ;
int Proc(char pszIn[],char pszOut[]) { int nLen=1; pszOut[0]='$'; int i=0; while(pszIn[i]!='\0') { pszOut[nLen++]='#'; pszOut[nLen++]=pszIn[i]; i++; } pszOut[nLen++]='#'; pszOut[nLen]=0; return nLen; } void Manacher(int *p,char *str,int len) { int mx=0,id=0; for(int i=0; i<len; i++) { p[i]=mx>i?min(p[2*id-i],mx-i):1; while(str[i+p[i]]==str[i-p[i]])p[i]++; if(i+p[i]>mx) { mx=i+p[i]; id=i; } } } const int MAXN=220010; char strIn[MAXN]; char strOut[MAXN]; int p[MAXN]; int main() { while(scanf("%s",strIn)!=EOF) { int nLen=Proc(strIn,strOut); Manacher(p,strOut,nLen); int ans=1; for(int i=0; i<nLen; i++) ans=max(ans,p[i]); printf("%d\n",ans-1); } return 0; }
struct Manacher { char str[MAXN]; int p[MAXN]; int n; void getP() { int mx=0,id=0; for(int i=0; i<n; i++) { p[i]=mx>i?min(p[2*id-i],mx-i):1; while(str[i+p[i]]==str[i-p[i]]) p[i]++; if(i+p[i]>mx) { mx=i+p[i]; id=i; } } } int call(char *s) { n=0; str[n++]='$'; for(; *s; s++) { str[n++]='#'; str[n++]=*s; } str[n++]='#'; str[n]=0; getP(); int ret=1; for(int i=0; i<n; i++) ret=max(ret,p[i]); return ret-1; } } soul;
int min_max_reprecention(int flag) { //最小最大表示法0、1 int i=0,j=1,k=0; while(i<wlen&&j<wlen&&k<wlen) { int t=word[(i+k)%wlen]-word[(j+k)%wlen]; if(!t) k++; else { if(flag==0) { if(t>0) i=i+k+1; else j=j+k+1; } else { if(t>0) j=j+k+1; else i=i+k+1; } if(i==j) j++; k=0; } } return i<j?i:j; } //返回是从0开始,如果问第几个需加1
///这些封装好的树都支持插入(insert)、删除(erase)、求kth(find_by_order)、求rank(order_of_key)操作 #include<cstdio> #include<ext/pb_ds/assoc_container.hpp> using namespace std; using namespace __gnu_pbds; int main() { /** * spoj3273, G++4.3.2, 4.66s * tree<int,null_mapped_type,less<int>,rb_tree_tag,tree_order_statistics_node_update> bbt; */ /** * spoj3273, G++4.3.2, TLE * tree<int,null_mapped_type,less<int>,splay_tree_tag,tree_order_statistics_node_update> bbt; */ /** * spoj3273, G++4.3.2, TLE * tree<int,null_mapped_type,less<int>,ov_tree_tag,tree_order_statistics_node_update> bbt; */ tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update> bbt; int n,num; char c; scanf("%d",&n); while(n--) { scanf(" %c%d",&c,&num); switch(c) { case 'I': bbt.insert(num); break; case 'D': bbt.erase(num); break; case 'K': num<=bbt.size()?printf("%d\n",*bbt.find_by_order(num-1)):puts("invalid"); break; case 'C': printf("%d\n",bbt.order_of_key(num)); break; } } } /* 此外,我手写了Treap和Size Balanced Tree(代码在此)并经过测试,前者3.94s,后者4.06s, 可见手写数据结构的速度总归要比封装好的要快,而封装好的实现中红黑树速度最快,这也是意料之中的。 关于声明变量时的参数,第一个是键(key)的类型;第二个是值(value)的类型,null_type表示没有值, 简单地理解就是表明这是set而不是map,注意SPOJ的G++版本稍旧(4.3.2),需要写成null_mapped_type才可以,我本地的G++版本为4.7.1; 第三个表示比较函数,默认为less<Type>;第四个为平衡二叉树的类型,默认为红黑树rb_tree_tag;第五个代表元素的维护策略, 只有当使用tree_order_statistics_node_update时才可以求kth和rank,此外还有null_tree_node_update(默认值)等,具体的区别在官方文档中有介绍(好吧我承认我没看懂= =)。 这里要注意的是,求kth(find_by_order)返回的是迭代器,求rank返回的是值,两者都是从0开始计算的。 此外,它们也支持合并(join)和分离(split)操作。用法如下。 tree<int,null_type> a,b; // 对两平衡二叉树进行一些操作 a.join(b); // 对两平衡二叉树进行一些操作 a.split(v,b); */
#include <bits/stdc++.h> using namespace std; const int N=55555,K=5; const int inf=0x3f3f3f3f; #define sqr(x) (x)*(x) int k,n,idx; //k为维数,n为点数 struct point { int x[K]; bool operator < (const point &u) const { return x[idx]<u.x[idx]; } } po[N]; typedef pair<double,point>tp; priority_queue<tp>nq; struct kdTree { point pt[N<<2]; int son[N<<2]; void build(int l,int r,int rt=1,int dep=0) { if(l>r) return; son[rt]=r-l; son[rt*2]=son[rt*2+1]=-1; idx=dep%k; int mid=(l+r)/2; nth_element(po+l,po+mid,po+r+1); pt[rt]=po[mid]; build(l,mid-1,rt*2,dep+1); build(mid+1,r,rt*2+1,dep+1); } void query(point p,int m,int rt=1,int dep=0) { if(son[rt]==-1) return; tp nd(0,pt[rt]); for(int i=0; i<k; i++) nd.first+=sqr(nd.second.x[i]-p.x[i]); int dim=dep%k,x=rt*2,y=rt*2+1,fg=0; if(p.x[dim]>=pt[rt].x[dim]) swap(x,y); if(~son[x]) query(p,m,x,dep+1); if(nq.size()<m) nq.push(nd),fg=1; else { if(nd.first<nq.top().first) nq.pop(),nq.push(nd); if(sqr(p.x[dim]-pt[rt].x[dim])<nq.top().first) fg=1; } if(~son[y]&&fg) query(p,m,y,dep+1); } } kd; void print(point &p) { for(int j=0; j<k; j++) printf("%d%c",p.x[j],j==k-1?'\n':' '); } int main() { while(scanf("%d%d",&n,&k)!=EOF) { for(int i=0; i<n; i++) for(int j=0; j<k; j++) scanf("%d",&po[i].x[j]); kd.build(0,n-1); int t,m; for(scanf("%d",&t); t--;) { point ask; for(int j=0; j<k; j++) scanf("%d",&ask.x[j]); scanf("%d",&m); kd.query(ask,m); printf("the closest %d points are:\n", m); point pt[20]; for(int j=0; !nq.empty(); j++) pt[j]=nq.top().second,nq.pop(); for(int j=m-1; j>=0; j--) print(pt[j]); } } return 0; }
【1】修改操作:将A[x]的值加上c;
【2】求和操作:求此时A[l..r]的和。
void ADD(int x, int c) { for (int i=x; i<=n; i+=i&(-i)) a[i] += c; } int SUM(int x) { int s = 0; for (int i=x; i>0; i-=i&(-i)) s += a[i]; return s; }
操作【1】:ADD(x, c);
操作【2】:SUM(r)-SUM(l-1)。
【1】修改操作:将A[l..r]之间的全部元素值加上c;
【2】求和操作:求此时A[x]的值。
void ADD(int x, int c) { for (int i=x; i>0; i-=i&(-i)) b[i] += c; } int SUM(int x) { int s = 0; for (int i=x; i<=n; i+=i&(-i)) s += b[i]; return s; }
void ADD_B(int x, int c) { for (int i=x; i>0; i-=i&(-i)) B[i] += c; } void ADD_C(int x, int c) { for (int i=x; i<=n; i+=i&(-i)) C[i] += x * c; } int SUM_B(int x) { int s = 0; for (int i=x; i<=n; i+=i&(-i)) s += B[i]; return s; } int SUM_C(int x) { int s = 0; for (int i=x; i>0; i-=i&(-i)) s += C[i]; return s; } inline int SUM(int x) { if (x) return SUM_B(x) * x + SUM_C(x - 1); else return 0; }
#include <bits/stdc++.h> using namespace std; const int MAXN = 1e4+100; struct Graph { SegTree tr; struct Edge { int to; int w; int next; } edges[MAXN<<1]; int head[MAXN],edge; void init() { memset(head,-1,sizeof(head)); cur=edge=0; wei[1]=0; } void addEdge(int u,int v,int w) { edges[edge].w=w,edges[edge].to=v,edges[edge].next=head[u],head[u]=edge++; edges[edge].w=w,edges[edge].to=u,edges[edge].next=head[v],head[v]=edge++; } int fa[MAXN],son[MAXN],dep[MAXN],wei[MAXN],num[MAXN]; void build(int u=1,int f=0,int d=0) { dep[u] = d; fa[u] = f; son[u]=-1; num[u]=1; for(int i = head[u]; i != -1; i = edges[i].next) { int v = edges[i].to; if(v != f) { build(v,u,d+1); wei[v]=edges[i].w; num[u] += num[v]; if(son[u] == -1 || num[v] > num[son[u]]) son[u] = v; } } } int seg[MAXN],top[MAXN],cur; void split(int u=1,int tp=1) { seg[u]=++cur; top[u]=tp; if(son[u]!=-1) split(son[u],tp); for(int i=head[u]; i!=-1; i=edges[i].next) { int v=edges[i].to; if(v==fa[u]||v==son[u]) continue; split(v,v); } } void call() { init(); int a,b,c; for(int i=1; i<n; i++) scanf("%d%d%d",&a,&b,&c),addEdge(a,b,c); build(); split(); for(int i=1; i<=n; i++) tr.update(seg[i],wei[i]); } } soul;
const int maxn=101010+5; const int maxm=maxn+maxn; struct EDGENODE { int to; int w; int next; } edges[maxm]; int head[maxn],edge; inline void init() { edge=0; memset(head,-1,sizeof(head)); } inline void addedge(int u,int v,int w) { edges[edge].w=w,edges[edge].to=v,edges[edge].next=head[u],head[u]=edge++; edges[edge].w=w,edges[edge].to=u,edges[edge].next=head[v],head[v]=edge++; } int que[maxn]; // 队列 bool vis[maxn]; // 访问标记 int son[maxn]; // 重儿子 int idx[maxn]; // 结点v在其路径中的编号 int dep[maxn]; // 结点v的深度 int siz[maxn]; // 以结点v为根的子树的结点个数 int belong[maxn]; // 结点v所属的路径编号 int fa[maxn]; // 结点v的父亲结点 int top[maxn]; // 编号为p的路径的顶端结点 int len[maxn]; // 路径p的长度 int sump[maxn]; // 路径p的编号 int seg[maxn]; // 结点v的父边在线段树中的位置 int wei[maxn]; // 结点v的父边的权值 int l,r,ans,cnt; int n; char cmd[22]; void split() { memset(dep,-1,sizeof(dep)); l=0; dep[ que[r=1]=1 ]=0; // 将根结点插入队列,并设深度为0 fa[1]=-1; // 默认 1 为根结点 wei[1]=0; while (l<r) { // 第一遍搜索求出 fa,dep,wei int u=que[++l]; vis[u]=false; // 顺便初始化vis for (int i=head[u]; i!=-1; i=edges[i].next) { int v=edges[i].to; int w=edges[i].w; if (dep[v]==-1) { // 未访问过的结点 dep[ que[++r]=v ]=dep[u]+1; // 将v插入队列并设深度为dep[u]+1 fa[v]=u; // v的父结点为u wei[v]=w; // v的父边权值 } } } cnt=0; // 重链编号 for (int i=n; i>0; i--) { int u=que[i],p=-1; siz[u]=1; son[u]=p; for (int k=head[u]; k!=-1; k=edges[k].next) { int v=edges[k].to; if (vis[v]) { // 若v是u的子结点 siz[u]+=siz[v]; // 计数 if (p==-1||siz[v]>siz[p]) { son[u]=v; p=v; // u的重儿子是v } } } if (p==-1) { // u是叶子结点 idx[u]=len[++cnt]=1; // 一个新的路径编号为cnt,u是路径中的第一个结点 belong[ top[cnt]=u ]=cnt; // u是顶端结点,且u属于路径cnt } else { // u不是叶子结点 idx[u]=++len[ belong[u]=belong[p] ]; // u属于重儿子所在的链,链长+1,u是路径中第len个结点 top[ belong[u] ]=u; // u是顶端结点 } vis[u]=true; // 访问标记 } } int find(int va,int vb) { int f1=top[belong[va]],f2=top[belong[vb]],tmp=-INF; while (f1!=f2) { if (dep[f1]<dep[f2]) { swap(f1,f2); swap(va,vb); } tmp=max(tmp,tr.query(1,seg[f1],seg[va])); va=fa[f1]; f1=top[belong[va]]; } if (va==vb) return tmp; if (dep[va]>dep[vb]) swap(va,vb); return max(tmp,tr.query(1,seg[son[va]],seg[vb])); } sump[0]=0; for (int i=1; i<=cnt; i++) sump[i]=sump[i-1]+len[i]; for (int i=1; i<=n; i++) { seg[i]=sump[ belong[i] ]-idx[i]+1; tr.num[ seg[i] ]=wei[i]; }
const int MAXN = 1e5+10; struct Node { Node*ch[2]; int r; int v; int son; void init(int _v) { v=_v; ch[0]=ch[1]=0; r=rand(); son=1; } int cmp(int x) const { if(x==v) return -1; return x<v?0:1; } void maintain() { son=1; if(ch[0]) son+=ch[0]->son; if(ch[1]) son+=ch[1]->son; } } nodePool[MAXN],*cur,*rt; struct Treap { Node* newNode(int v=0) { cur->init(v); return cur++; } void init() { cur=nodePool; rt=NULL; } void rotate(Node *o,int d) { Node *k= o->ch[d^1]; o->ch[d^1] = k->ch[d]; k->ch[d]=o; o->maintain(); k->maintain(); o=k; } void insert(Node* &o,int x) { if(o==NULL) o = newNode(x); else { ///multiset int d=(x<o->v?0:1); ///set use cmp() and check -1; insert(o->ch[d],x); if( o->ch[d]->r> o->r) rotate(o,d^1); } o->maintain(); } void remove(Node*&o,int x) { int d=o->cmp(x); if(d==-1) { Node*u=o; if(o->ch[0]!=NULL&&o->ch[1]!=NULL) { int d2=o->ch[0]->r>o->ch[1]->r?1:0; rotate(o,d2); remove(o->ch[d2],x); } else { if(o->ch[0]==NULL) o=o->ch[1]; else o=o->ch[0]; } } else { remove(o->ch[d],x); if(o!=NULL) o->maintain(); } } int kth(Node *o,int k) { if(o==NULL||k<=0||k>o->son) return 0; int s=(o->ch[1]==NULL?0:o->ch[1]->son); if(k==s+1) return o->v; else if(k<=s) return kth(o->ch[1],k); else return kth(o->ch[0],k-s-1); } void mergeto(Node *&src,Node *&dest) { if(src->ch[0]!=NULL) mergeto(src->ch[0],dest); if(src->ch[1]!=NULL) mergeto(src->ch[1],dest); insert(dest,src->v); src=NULL; } };
const int MAXN = 1e5+10; struct Node { Node*ch[2]; int v; int son; /***FLIP***\ 大白P243 operation to call: Node *left,*mid,*right,*o; split(root,a,left,0); split(o,b-a+1,mid,right); mid->flip^=1; root=merge(merge(left,right),mid); ATTENTION! need a virtual point at BEGIN \***FLIP***/ int flip; void pushdown() { if(flip) { flip=0; swap(ch[0],ch[1]); ch[0]->flip=!ch[0]->flip; ch[1]->flip=!ch[1]->flip; } } void init(int _v); int cmp(int x) const { if(x==v) return -1; return x<v?0:1; } void maintain() { son=1; if(ch[0]) son+=ch[0]->son; if(ch[1]) son+=ch[1]->son; } } nodePool[MAXN],*cur,*rt,*null; void Node::init(int v) { v=_v; ch[0]=ch[1]=null; r=rand(); son=1; flip=0; } void initNULL() { null=new Node(); null->init(0); null->son=0; } struct Treap { Node* newNode(int v=0) { cur->init(v); return cur++; } void init() { cur=nodePool; rt=NULL; } void rotate(Node *o,int d) { Node *k= o->ch[d^1]; o->ch[d^1] = k->ch[d]; k->ch[d]=o; o->maintain(); k->maintain(); o=k; } void splay(Node *&o,int k) { int d=o->cmp(k); if(d==1) k-=o->ch[0]->son+1; if(d!=-1) { Node *p=o->ch[d]; int d2=p->cmp(k); int k2=(d2==0?k:k-p->ch[0]->son-1); if(d2!=-1) { splay(p->ch[d2],k2); if(d==d2) rotate(o,d^1); else rotate(o->ch[d],d); } rotate(o,d^1); } } ///right NOT NULL Node *merge(Node*left,Node*right) { splay(left,left->s); left->ch[1]=right; left->maintain(); return left; } ///ATTENTION: ///前K小在left ///k=[1,o->son]; void split(Node*o,int k,Node*&left,Node*&right) { splay(o,k); left=o; right=o->ch[1]; o->ch[1]=null; left->maintain(); } };
#include <bits/stdc++.h> using namespace std; const int MAXN = 60010; const int M = 2500010; int n,q,m,tot; int a[MAXN], t[MAXN]; int T[MAXN], lson[M], rson[M],c[M]; int S[MAXN]; struct Query { int kind; int l,r,k; } query[10010]; void Init_hash(int k) { sort(t,t+k); m = unique(t,t+k) - t; } int hash(int x) { return lower_bound(t,t+m,x)-t; } int build(int l,int r) { int root = tot++; c[root] = 0; if(l != r) { int mid = (l+r)/2; lson[root] = build(l,mid); rson[root] = build(mid+1,r); } return root; } int Insert(int root,int pos,int val) { int newroot = tot++, tmp = newroot; int l = 0, r = m-1; c[newroot] = c[root] + val; while(l < r) { int mid = (l+r)>>1; if(pos <= mid) { lson[newroot] = tot++; rson[newroot] = rson[root]; newroot = lson[newroot]; root = lson[root]; r = mid; } else { rson[newroot] = tot++; lson[newroot] = lson[root]; newroot = rson[newroot]; root = rson[root]; l = mid+1; } c[newroot] = c[root] + val; } return tmp; } int lowbit(int x) { return x&(-x); } int use[MAXN]; void add(int x,int pos,int val) { while(x <= n) { S[x] = Insert(S[x],pos,val); x += lowbit(x); } } int sum(int x) { int ret = 0; while(x > 0) { ret += c[lson[use[x]]]; x -= lowbit(x); } return ret; } int Query(int left,int right,int k) { int left_root = T[left-1]; int right_root = T[right]; int l = 0, r = m-1; for(int i = left-1; i; i -= lowbit(i)) use[i] = S[i]; for(int i = right; i ; i -= lowbit(i)) use[i] = S[i]; while(l < r) { int mid = (l+r)/2; int tmp = sum(right) - sum(left-1) + c[lson[right_root]] - c[lson[left_root]]; if(tmp >= k) { r = mid; for(int i = left-1; i ; i -= lowbit(i)) use[i] = lson[use[i]]; for(int i = right; i; i -= lowbit(i)) use[i] = lson[use[i]]; left_root = lson[left_root]; right_root = lson[right_root]; } else { l = mid+1; k -= tmp; for(int i = left-1; i; i -= lowbit(i)) use[i] = rson[use[i]]; for(int i = right; i ; i -= lowbit(i)) use[i] = rson[use[i]]; left_root = rson[left_root]; right_root = rson[right_root]; } } return l; } void Modify(int x,int p,int d) { while(x <= n) { S[x] = Insert(S[x],p,d); x += lowbit(x); } } int main() { int Tcase; scanf("%d",&Tcase); while(Tcase--) { scanf("%d%d",&n,&q); tot = 0; m = 0; for(int i = 1; i <= n; i++) { scanf("%d",&a[i]); t[m++] = a[i]; } char op[10]; for(int i = 0; i < q; i++) { scanf("%s",op); if(op[0] == 'Q') { query[i].kind = 0; scanf("%d%d%d",&query[i].l,&query[i].r,&query[i].k); } else { query[i].kind = 1; scanf("%d%d",&query[i].l,&query[i].r); t[m++] = query[i].r; } } Init_hash(m); T[0] = build(0,m-1); for(int i = 1; i <= n; i++) T[i] = Insert(T[i-1],hash(a[i]),1); for(int i = 1; i <= n; i++) S[i] = T[0]; for(int i = 0; i < q; i++) { if(query[i].kind == 0) printf("%d\n",t[Query(query[i].l,query[i].r,query[i].k)]); else { Modify(query[i].l,hash(a[query[i].l]),-1); Modify(query[i].l,hash(query[i].r),1); a[query[i].l] = query[i].r; } } } return 0; }
/**** 第一行是N和M,表示有这棵树有N个点M个询问 然后是N-1行,每行x,y表示x-y有一条边 接下去是N行,每行是一个数字,表示每个点的权值 后面一行表示根 接下来是M行 第一个数字是K K=0 表示子树修改,后面x,y,表示以x为根的子树的点权值改成y K=1 表示换根,后面x,表示把这棵树的根变成x K=2 表示链修改,后面x,y,z,表示把这棵树中x-y的路径上点权值改成z K=3 表示子树询问min,后面x,表示以x为根的子树中点的权值min K=4 表示子树询问max,后面x,表示以x为根的子树中点的权值max K=5 表示子树加,后面x,y,表示x为根的子树中点的权值+y K=6 表示链加,后面x,y,z,表示把这棵树中x-y的路径上点权值改成+z K=7 表示链询问min,后面x,y,表示把这棵树中x-y的路径上点的min K=8 表示链询问max,后面x,y,表示把这棵树中x-y的路径上点的max K=9 表示换父亲,后面x,y,表示把x的父亲换成y,如果y在x子树里不操作。 K=10 表示链询问sum,后面x,y,z,表示表示把这棵树中x-y的路径上点的sum K=11 表示子树询问sum,后面x,表示以x为根的子树的点权sum 垃圾回收: 由于add操作会新增大量内部白点,但是内部白点最多同时只有O(n)个,所以需要垃圾回收。 效率: 时间复杂度为O(logn)每次操作,但是常数为97,非常大。 */ #include<cstdio> #define N 200010 const int inf=~0U>>1; inline void swap(int&a,int&b) { int c=a; a=b; b=c; } inline int max(int a,int b) { return a>b?a:b; } inline int min(int a,int b) { return a<b?a:b; } inline void read(int&a) { char c; bool f=0; a=0; while(!((((c=getchar())>='0')&&(c<='9'))||(c=='-'))); if(c!='-')a=c-'0'; else f=1; while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0'; if(f)a=-a; } struct tag { int a,b;//ax+b tag() { a=1,b=0; } tag(int x,int y) { a=x,b=y; } inline bool ex() { return a!=1||b; } inline tag operator+(const tag&x) { return tag(a*x.a,b*x.a+x.b); } }; inline int atag(int x,tag y) { return x*y.a+y.b; } struct data { int sum,minv,maxv,size; data() { sum=size=0,minv=inf,maxv=-inf; } data(int x) { sum=minv=maxv=x,size=1; } data(int a,int b,int c,int d) { sum=a,minv=b,maxv=c,size=d; } inline data operator+(const data&x) { return data(sum+x.sum,min(minv,x.minv),max(maxv,x.maxv),size+x.size); } }; inline data operator+(const data&a,const tag&b) { return a.size?data(a.sum*b.a+a.size*b.b,atag(a.minv,b),atag(a.maxv,b),a.size):a; } //son:0-1:重链儿子,2-3:AAA树儿子 int f[N],son[N][4],a[N],tot,rt,rub,ru[N]; bool rev[N],in[N]; int val[N]; data csum[N],tsum[N],asum[N]; tag ctag[N],ttag[N]; inline bool isroot(int x,int t) { if(t)return !f[x]||!in[f[x]]||!in[x]; return !f[x]||(son[f[x]][0]!=x&&son[f[x]][1]!=x)||in[f[x]]||in[x]; } inline void rev1(int x) { if(!x)return; swap(son[x][0],son[x][1]); rev[x]^=1; } inline void tagchain(int x,tag p) { if(!x)return; csum[x]=csum[x]+p; asum[x]=csum[x]+tsum[x]; val[x]=atag(val[x],p); ctag[x]=ctag[x]+p; } inline void tagtree(int x,tag p,bool t) { if(!x)return; tsum[x]=tsum[x]+p; ttag[x]=ttag[x]+p; if(!in[x]&&t)tagchain(x,p); else asum[x]=csum[x]+tsum[x]; } inline void pb(int x) { if(!x)return; if(rev[x])rev1(son[x][0]),rev1(son[x][1]),rev[x]=0; if(!in[x]&&ctag[x].ex())tagchain(son[x][0],ctag[x]),tagchain(son[x][1],ctag[x]),ctag[x]=tag(); if(ttag[x].ex()) { tagtree(son[x][0],ttag[x],0),tagtree(son[x][1],ttag[x],0); tagtree(son[x][2],ttag[x],1),tagtree(son[x][3],ttag[x],1); ttag[x]=tag(); } } inline void up(int x) { tsum[x]=data(); for(int i=0; i<2; i++)if(son[x][i])tsum[x]=tsum[x]+tsum[son[x][i]]; for(int i=2; i<4; i++)if(son[x][i])tsum[x]=tsum[x]+asum[son[x][i]]; if(in[x]) { csum[x]=data(); asum[x]=tsum[x]; } else { csum[x]=data(val[x]); for(int i=0; i<2; i++)if(son[x][i])csum[x]=csum[x]+csum[son[x][i]]; asum[x]=csum[x]+tsum[x]; } } inline int child(int x,int t) { pb(son[x][t]); return son[x][t]; } inline void rotate(int x,int t) { int y=f[x],w=(son[y][t+1]==x)+t; son[y][w]=son[x][w^1]; if(son[x][w^1])f[son[x][w^1]]=y; if(f[y])for(int z=f[y],i=0; i<4; i++)if(son[z][i]==y)son[z][i]=x; f[x]=f[y]; f[y]=x; son[x][w^1]=y; up(y); } inline void splay(int x,int t=0) { int s=1,i=x,y; a[1]=i; while(!isroot(i,t))a[++s]=i=f[i]; while(s)pb(a[s--]); while(!isroot(x,t)) { y=f[x]; if(!isroot(y,t)) { if((son[f[y]][t]==y)^(son[y][t]==x))rotate(x,t); else rotate(y,t); } rotate(x,t); } up(x); } inline int newnode() { int x=rub?ru[rub--]:++tot; son[x][2]=son[x][3]=0; in[x]=1; return x; } inline void setson(int x,int t,int y) { son[x][t]=y; f[y]=x; } inline int pos(int x) { for(int i=0; i<4; i++)if(son[f[x]][i]==x)return i; return 4; } inline void add(int x,int y) { //从x连出一条虚边到y if(!y)return; pb(x); for(int i=2; i<4; i++)if(!son[x][i]) { setson(x,i,y); return; } while(son[x][2]&&in[son[x][2]])x=child(x,2); int z=newnode(); setson(z,2,son[x][2]); setson(z,3,y); setson(x,2,z); splay(z,2); } inline void del(int x) { //将x与其虚边上的父亲断开 if(!x)return; splay(x); if(!f[x])return; int y=f[x]; if(in[y]) { int s=1,i=y,z=f[y]; a[1]=i; while(!isroot(i,2))a[++s]=i=f[i]; while(s)pb(a[s--]); if(z) { setson(z,pos(y),child(y,pos(x)^1)); splay(z,2); } ru[++rub]=y; } else { son[y][pos(x)]=0; splay(y); } f[x]=0; } inline int fa(int x) { //x通过虚边的父亲 splay(x); if(!f[x])return 0; if(!in[f[x]])return f[x]; int t=f[x]; splay(t,2); return f[t]; } inline int access(int x) { int y=0; for(; x; y=x,x=fa(x)) { splay(x); del(y); add(x,son[x][1]); setson(x,1,y); up(x); } return y; } inline int lca(int x,int y) { access(x); return access(y); } inline int root(int x) { access(x); splay(x); while(son[x][0])x=son[x][0]; return x; } inline void makeroot(int x) { access(x); splay(x); rev1(x); } inline void link(int x,int y) { makeroot(x); add(y,x); access(x); } inline void cut(int x) { access(x); splay(x); f[son[x][0]]=0; son[x][0]=0; up(x); } inline void changechain(int x,int y,tag p) { makeroot(x); access(y); splay(y); tagchain(y,p); } inline data askchain(int x,int y) { makeroot(x); access(y); splay(y); return csum[y]; } inline void changetree(int x,tag p) { access(x); splay(x); val[x]=atag(val[x],p); for(int i=2; i<4; i++)if(son[x][i])tagtree(son[x][i],p,1); up(x); splay(x); } inline data asktree(int x) { access(x); splay(x); data t=data(val[x]); for(int i=2; i<4; i++)if(son[x][i])t=t+asum[son[x][i]]; return t; } int n,m,x,y,z,k,i,ed[N][2]; int main() { read(n); read(m); tot=n; for(i=1; i<n; i++)read(ed[i][0]),read(ed[i][1]); for(i=1; i<=n; i++)read(val[i]),up(i); for(i=1; i<n; i++)link(ed[i][0],ed[i][1]); read(rt); makeroot(rt); while(m--) { read(k); if(k==1) { //换根 read(rt); makeroot(rt); } if(k==9) { //x的父亲变成y read(x),read(y); if(lca(x,y)==x)continue; cut(x); link(y,x); makeroot(rt); } if(k==0) { //子树赋值 read(x),read(y); changetree(x,tag(0,y)); } if(k==5) { //子树加 read(x),read(y); changetree(x,tag(1,y)); } if(k==3) { //子树最小值 read(x); printf("%d\n",asktree(x).minv); } if(k==4) { //子树最大值 read(x); printf("%d\n",asktree(x).maxv); } if(k==11) { //子树和 read(x); printf("%d\n",asktree(x).sum); } if(k==2) { //链赋值 read(x),read(y),read(z); changechain(x,y,tag(0,z)); makeroot(rt); } if(k==6) { //链加 read(x),read(y),read(z); changechain(x,y,tag(1,z)); makeroot(rt); } if(k==7) { //链最小值 read(x),read(y); printf("%d\n",askchain(x,y).minv); makeroot(rt); } if(k==8) { //链最大值 read(x),read(y); printf("%d\n",askchain(x,y).maxv); makeroot(rt); } if(k==10) { //链和 read(x),read(y); printf("%d\n",askchain(x,y).sum); makeroot(rt); } } return 0; }