@Pinetrie
2019-10-19T23:53:22.000000Z
字数 8939
阅读 965
题目描述
如题,已知一棵包含N个结点的树(连通且无环),每个节点上包含一个数值,需要支持以下操作:
操作1: 格式: 1 x y z 表示将树从x到y结点最短路径上所有节点的值都加上z
操作2: 格式: 2 x y 表示求树从x到y结点最短路径上所有节点的值之和
操作3: 格式: 3 x z 表示将以x为根节点的子树内所有节点值都加上z
操作4: 格式: 4 x 表示求以x为根节点的子树内所有节点值之和
输入格式:
第一行包含4个正整数N、M、R、P,分别表示树的结点个数、操作个数、根节点序号和取模数(即所有的输出结果均对此取模)。
接下来一行包含N个非负整数,分别依次表示各个节点上初始的数值。
接下来N-1行每行包含两个整数x、y,表示点x和点y之间连有一条边(保证无环且连通)
接下来M行每行包含若干个正整数,每行表示一个操作,格式如下:
操作1: 1 x y z
操作2: 2 x y
操作3: 3 x z
操作4: 4 x
输出格式:
输出包含若干行,分别依次表示每个操作2或操作4所得的结果(对P取模)
#include <bits/stdc++.h>using namespace std;typedef long long ll;const int maxn = 100010;ll w[maxn],root;ll N,M,R,P;//线段树///////////////////////////////////////////////////////////////////ll A[maxn<<2],Sum[maxn<<2],Add[maxn<<2];void Pushup(ll rt){Sum[rt] = (Sum[rt<<1] + Sum[rt<<1|1]) % P;}void Pushdown(ll rt,ll ln,ll rn){if(Add[rt]){Add[rt<<1] = (Add[rt<<1] + Add[rt]) % P;Add[rt<<1|1] = (Add[rt<<1|1] + Add[rt]) % P;Sum[rt<<1] = (Sum[rt<<1] + ln * Add[rt]) % P;Sum[rt<<1|1] = (Sum[rt<<1|1] + rn * Add[rt]) % P;Add[rt] = 0;}}void build(ll l,ll r,ll rt){if(l == r){Sum[rt] = A[l];return;}ll m = (l + r)>>1;build(l,m,rt<<1);build(m + 1,r,rt<<1|1);Pushup(rt);}ll query(ll L,ll R,ll l,ll r,ll rt){if(L <= l && R >= r){return Sum[rt];}ll m = (l + r)>>1;Pushdown(rt,m - l + 1,r - m);ll Ans = 0;if(L <= m) Ans = (Ans + query(L,R,l,m,rt<<1)) % P;if(R > m) Ans = (Ans + query(L,R,m + 1,r,rt<<1|1)) % P;return Ans;}void update(ll L,ll R,ll C,ll l,ll r,ll rt){if(L <= l && R >= r){Sum[rt] = (Sum[rt] + (r - l + 1) * C) % P;Add[rt] = (Add[rt] + C) % P;return;}ll m = (l + r)>>1;Pushdown(rt,m - l + 1,r - m);if(L <= m) update(L,R,C,l,m,rt<<1);if(R > m) update(L,R,C,m + 1,r,rt<<1|1);Pushup(rt);}//////////////////////////////////////////////////////////预处理///////////////////////////////////////////////////ll head[maxn],f[maxn],dep[maxn],siz[maxn],son[maxn],rk[maxn],top[maxn],id[maxn];ll tot,cnt;struct Edge{ll v,next;}e[maxn * 2];void addnode(ll u,ll v){e[tot].v = v;e[tot].next = head[u];head[u] = tot++;}void dfs1(ll u,ll fa,ll deep){f[u] = fa;dep[u] = deep;siz[u] = 1;for(ll i = head[u];i != -1;i = e[i].next){ll v = e[i].v;if(v == fa) continue;dfs1(v,u,deep + 1);siz[u] += siz[v];if(siz[v] > siz[son[u]]) son[u] = v;}}void dfs2(ll u,ll t){top[u] = t;id[u] = ++cnt;rk[cnt] = u;if(!son[u]) return;dfs2(son[u],t);for(ll i = head[u];i != -1;i = e[i].next){ll v = e[i].v;if(v != son[u] && v != f[u]) dfs2(v,v);}}询问//////////////////////////////////////////ll getsum(ll x,ll y){ll ans = 0,fx = top[x],fy = top[y];while(fx != fy){if(dep[fx] >= dep[fy]){ans = (ans + query(id[fx],id[x],1,N,1)) % P;x = f[fx],fx = top[x];}else{ans = (ans + query(id[fy],id[y],1,N,1)) % P;y = f[fy],fy = top[y];}}if(id[x] <= id[y]) ans = (ans + query(id[x],id[y],1,N,1)) % P;else ans = (ans + query(id[y],id[x],1,N,1)) % P;return ans;}void getupdate(ll x,ll y,ll C){ll fx = top[x],fy = top[y];while(fx != fy){if(dep[fx] >= dep[fy]){update(id[fx],id[x],C,1,N,1);x = f[fx],fx = top[x];}else{update(id[fy],id[y],C,1,N,1);y = f[fy],fy = top[y];}}if(id[x] <= id[y]) update(id[x],id[y],C,1,N,1);else update(id[y],id[x],C,1,N,1);}ll getsonsum(ll x){return query(id[x],id[x] + siz[x] - 1,1,N,1);}void getsonupdate(ll x,ll z){update(id[x],id[x] + siz[x] - 1,z,1,N,1);}int main(){memset(head,-1,sizeof(head));scanf("%lld %lld %lld %lld",&N,&M,&R,&P);for(ll i = 1;i <= N;i++) scanf("%lld",&w[i]);for(ll i = 1;i < N;i++){ll u,v;scanf("%lld %lld",&u,&v);addnode(u,v);addnode(v,u);}dfs1(R,0,1);dfs2(R,R);for(ll i = 1;i <= N;i++){A[i] = w[rk[i]];}build(1,N,1);while(M--){ll op,x,y,z;scanf("%lld",&op);if(op == 1){scanf("%lld %lld %lld",&x,&y,&z);getupdate(x,y,z);}if(op == 2){scanf("%lld %lld",&x,&y);printf("%lld\n",getsum(x,y));}if(op == 3){scanf("%lld %lld",&x,&z);getsonupdate(x,z);}if(op == 4){scanf("%lld",&x);printf("%lld\n",getsonsum(x));}}return 0;}
#include <bits/stdc++.h>using namespace std;const int maxn = 100010;int T,n,m,np;int L[maxn*20],R[maxn*20],Sum[maxn*20],A[maxn],B[maxn],Root[maxn];int build(int l,int r){int rt = ++np;Sum[rt] = 0;if(l < r){int mid = (l + r) / 2;L[rt] = build(l,mid);R[rt] = build(mid + 1,r);}return rt;}int update(int pre,int l,int r,int x){int rt = ++np;L[rt] = L[pre],R[rt] = R[pre],Sum[rt] = Sum[pre] + 1;int mid = (l + r) / 2;if(l < r){if(x <= mid) L[rt] = update(L[pre],l,mid,x);else R[rt] = update(R[pre],mid + 1,r,x);}return rt;}int query(int u,int v,int l,int r,int k){if(l >= r) return l;int mid = (l + r) / 2;int x = Sum[L[v]] - Sum[L[u]];if(x >= k) return query(L[u],L[v],l,mid,k);else return query(R[u],R[v],mid + 1,r,k - x);}int main(){int T;scanf("%d",&T);while(T--){np = 0;scanf("%d %d",&n,&m);for(int i = 1;i <= n;i++){scanf("%d",&A[i]);B[i] = A[i];}sort(B + 1,B + 1 + n);int len = unique(B + 1,B + 1 + n) - (B + 1);Root[0] = build(1,len);for(int i = 1;i <= n;i++){int p = lower_bound(B + 1,B + 1 + len,A[i]) - B;Root[i] = update(Root[i - 1],1,len,p);}while(m--){int x,y,z;scanf("%d %d %d",&x,&y,&z);int p = query(Root[x - 1],Root[y],1,len,z);printf("%d\n",B[p]);}}return 0;}
线性基的性质:
1、原序列里面的任意一个数都可以由线性基里面的一些数异或得到。
2、线性基里面的任意一些数异或起来都不能得到0。
3、线性基里面的数的个数唯一,并且在保持性质一的前提下,数的个数是最少的。
struct LineBase{ll b[66];//上三角矩阵ll p[66];//对角矩阵int cnt;int max_b = 63;void init(){memset(b,0,sizeof(b));memset(p,0,sizeof(p));cnt = 0;}bool Insert(ll x)//插入{for(int i = max_b;i >= 0;i--){if((x>>i)&1){if(b[i] == 0){b[i] = x;break;}x = x^b[i];}}if(x > 0) cnt++;return (x > 0);}LineBase Merge(LineBase n1,LineBase n2)//线性基合并{LineBase ret = n1;for(int i = 0;i <= max_b;i++){if(n2.b[i]) ret.Insert(n2.b[i]);}return ret;}LineBase Merge2(LineBase A,LineBase B)//线性基求交{LineBase All,C,D;All.init();C.init();D.init();for(ll i = 60;i >= 0;i--){All.b[i] = A.b[i];D.b[i] = 1ll<<i;}for(ll i = 60;i >= 0;i--){if(B.b[i]){ll v = B.b[i],k = 0;bool can = true;for(ll j = 60;j >= 0;j--){if(v & (1ll<<j)){if(All.b[j]){v^=All.b[j];k^=D.b[j];}else{can = false;All.b[j] = v;D.b[j] = k;break;}}}if(can){ll v = 0;for(ll j = 60;j >= 0;j--){if(k & (1ll<<j)){v^=A.b[j];}}C.Insert(v);}}}return C;}ll queryMax(ll x)//求最大{ll ans = x;for(int i = max_b;i >= 0;i--){if((ans^b[i]) > ans) ans^=b[i];}return ans;}ll queryMin()//求最小{for(int i = 0;i < max_b;i++){if(b[i]) return b[i];}return 0;}void rebuild()//化为对角矩阵{for(int i = max_b;i >= 0;i--){for(int j = i - 1;j >= 0;j--){if(b[i]&(1ll<<j)) b[i]^=b[j];}}cnt = 0;for(int i = 0;i <= max_b;i++){if(b[i]) p[cnt++] = b[i];}}ll kthquery(ll k)//求第k大(必须先化为对角矩阵){ll ans = 0;if(k >= (1ll<<cnt)) return -1;for(int i = max_b;i >= 0;i--){if(k&(1ll<<i)) ans^=p[i];}return ans;}};
输入前几项数据,快速求解线性递推式的第n项。
#include <bits/stdc++.h>using namespace std;namespace linear_seq{#define rep(i,a,n) for(int i = a;i < n;i++)#define per(i,a,n) for(int i = n - 1;i >= a;i--)#define pb push_back#define mp make_pari#define all(x) (x).begin(),(x).end()#define fi first#define se second#define SZ(x) ((int)(x).size())typedef vector<int> VI;typedef pair<int,int> PII;typedef long long ll;const ll mod = 1e9 + 7;const int N = 100010;ll res[N],base[N],_c[N],_md[N];ll modpow(ll a,ll b,ll mod) {ll res = 1;a %= mod;for(;b;b>>=1){if(b&1)res = res*a%mod;a=a*a%mod;}return res;}vector<int> Md;void mul(ll *a,ll *b,ll k){rep(i,0,k+k) _c[i] = 0;rep(i,0,k) if(a[i]) rep(j,0,k) _c[i+j]=(_c[i+j]+a[i]*b[j])%mod;for(int i = k+k-1;i>=k;i--) if(_c[i])rep(j,0,SZ(Md)) _c[i-k+Md[j]]=(_c[i-k+Md[j]]-_c[i]*_md[Md[j]])%mod;rep(i,0,k) a[i]=_c[i];}int solve(ll n,VI a,VI b){ll ans=0,pnt=0;int k=SZ(a);rep(i,0,k) _md[k-1-i]=-a[i];_md[k]=1;Md.clear();rep(i,0,k) if(_md[i]!=0) Md.push_back(i);rep(i,0,k) res[i]=base[i]=0;res[0]=1;while((1ll<<pnt)<=n) pnt++;for(int p=pnt;p>=0;p--){mul(res,res,k);if((n>>p)&1){for(int i=k-1;i>=0;i--) res[i+1]=res[i];res[0]=0;rep(j,0,SZ(Md)) res[Md[j]]=(res[Md[j]]-res[k]*_md[Md[j]])%mod;}}rep(i,0,k) ans=(ans+res[i]*b[i])%mod;if(ans<0) ans+=mod;return ans;}VI BM(VI s){VI C(1,1),B(1,1);int L=0,m=1,b=1;rep(n,0,SZ(s)){ll d=0;rep(i,0,L+1) d=(d+(ll)C[i]*s[n-i])%mod;if(d==0) ++m;else if(2*L<=n){VI T=C;ll c=mod-d*modpow(b,mod-2,mod)%mod;while(SZ(C)<SZ(B)+m) C.pb(0);rep(i,0,SZ(B)) C[i+m]=(C[i+m]+c*B[i])%mod;L=n+1-L;B=T;b=d;m=1;}else{ll c=mod-d*modpow(b,mod-2,mod)%mod;while(SZ(C)<SZ(B)+m) C.pb(0);rep(i,0,SZ(B)) C[i+m]=(C[i+m]+c*B[i])%mod;++m;}}return C;}int gao(VI a,ll n){VI c=BM(a);c.erase(c.begin());rep(i,0,SZ(c)) c[i]=(mod-c[i])%mod;return solve(n,c,VI(a.begin(),a.begin()+SZ(c)));}}typedef long long ll;const int MOD = 1e9 + 7;ll n,k;ll dp[2050];ll powMod(ll a,ll b){ll res = 1;while(b){if(b % 2 == 1) res = res * a % MOD;a = a * a % MOD;b /= 2;}return res;}int main(){int T;scanf("%d",&T);while(T--){scanf("%lld %lld",&k,&n);if(n == -1){ll ans = 2;ans = ans * powMod(k + 1,MOD - 2) % MOD;printf("%lld\n",ans);continue;}ll p = powMod(k,MOD - 2);//把递推式的前2 * k项计算出来并放入vetor中vector<int>v;v.push_back(1);dp[0] = 1;for(int i = 1;i <= 2 * k;i++){dp[i] = 0;for(int j = i - 1;j >= max(0ll,i - k);j--){dp[i] = (dp[i] + dp[j] * p % MOD) % MOD;}v.push_back(dp[i]);}//调用函数计算得到第n项的值ll ans = linear_seq::gao(v,n);printf("%lld\n",ans);}return 0;}
ans * ans =(同余) n % p
#include <bits/stdc++.h>using namespace std;typedef long long ll;ll w;ll p;bool ok;ll powMod(ll a,ll b){ll res = 1;while(b){if(b&1) res = res * a % p;a = a * a % p;b /= 2;}return res;}struct QuadraticField{ll x,y;QuadraticField operator*(QuadraticField T){QuadraticField ans;ans.x = (this->x * T.x % p + this->y * T.y % p * w % p) % p;ans.y = (this->x * T.y % p + this->y * T.x % p) % p;return ans;}QuadraticField operator^(ll b){QuadraticField ans;QuadraticField a = *this;ans.x = 1;ans.y = 0;while(b){if(b & 1){ans = ans * a;b--;}b /= 2;a = a * a;}return ans;}};ll Lengender(ll a){ll ans = powMod(a,(p - 1) / 2);if(ans + 1 == p) return -1;else return ans;}ll GetW(ll n,ll a){return ((a * a - n) % p + p) % p;}ll Solve(ll n){ll a;if(p == 2) return n;if(Lengender(n) == -1) ok = false;srand((unsigned)time(NULL));while(1){a = rand() % p;w = GetW(n,a);if(Lengender(w) == -1) break;}QuadraticField ans,res;res.x = a;res.y = 1;ans = res ^ ((p + 1) / 2);return ans.x;}int main(){ll n,ans1,ans2;while(scanf("%lld %lld",&n,&p) != EOF){ok = true;n %= p;ans1 = Solve(n);ans2 = p - ans1;if(!ok) printf("-1\n");else printf("%lld %lld\n",ans1,ans2);}return 0;}