2017 UESTC Training for Data Structures
2017 UESTC Training for Data Structures
A 水,找区间极差,RMQ怼上去。
#include<bits/stdc++.h> using namespace std; #pragma comment(linker, "/STACK:102400000,102400000") #define rep(i,a,b) for (int i=a;i<=b;i++) #define per(i,b,a) for (int i=b;i>=a;i--) #define mes(a,b) memset(a,b,sizeof(a)) #define INF 0x3f3f3f3f typedef long long ll; const int N = 200005; int a[N], f1[N][20], f2[N][20]; void RMQ(int n) { rep(i,1,n) f1[i][0]=f2[i][0]=a[i]; rep(j,1,19) rep(i,1,n) { if(i+(1<<j)-1<=n) { f1[i][j]=max(f1[i][j-1], f1[i+(1<<(j-1))][j-1]); f2[i][j]=min(f2[i][j-1], f2[i+(1<<(j-1))][j-1]); } } } int main() { int n, q; scanf("%d %d", &n, &q); rep(i,1,n) scanf("%d", &a[i]); RMQ(n); int l, r; rep(i,1,q) { scanf("%d %d", &l, &r); int lg=floor(log10(r-l+1)/log10(2)); int maxn=max(f1[l][lg], f1[r-(1<<lg)+1][lg]); int minn=min(f2[l][lg], f2[r-(1<<lg)+1][lg]); printf("%d\n", maxn-minn); } return 0; }
C 线段树区间更新,区间求和。
题意:N个数排成一列,有三种操作。1.给一段区间内的每个数乘上一个非负整数。2.给一段区间内的每个数加上一个非负整数.3.询问一段区间的和模上P的值。
tags:由于需要区间加add和区间乘mul,需要维护两个延迟标记。对于add,修改c,则sum+=c*len(区间长度),add+c;对于mul,修改c,则sum*=c;add*=c,mul*=c。乘法分配律(add+sum)*c = add*c+sum*c;
#include<bits/stdc++.h> using namespace std; #pragma comment(linker, "/STACK:102400000,102400000") #define rep(i,a,b) for (int i=a;i<=b;i++) #define per(i,b,a) for (int i=b;i>=a;i--) #define mes(a,b) memset(a,b,sizeof(a)) #define INF 0x3f3f3f3f #define MP make_pair #define PB push_back #define fi first #define se second typedef long long ll; const int N = 100005, M = N<<2; int n, m; ll mod, laz1[M], laz2[M], tr[M]; //laz1[]乘的延迟标记,laz2[]加的延迟标记 void Init() { rep(i,0,M-1) laz1[i]=1; } ll add(ll x, ll y) { return ((x%mod) + (y%mod))%mod; } ll mul(ll x, ll y) { return ((x%mod) * (y%mod))%mod; } void pushup(int pos) { tr[pos]=add(tr[pos<<1], tr[pos<<1|1]); } void build(int pos, int l, int r) { if(l==r) { scanf("%lld", &tr[pos]); tr[pos]%=mod; return ; } int mid=(l+r)>>1; build(pos<<1, l, mid); build(pos<<1|1, mid+1, r); pushup(pos); } void pushdown(int pos, int len) { int lson=pos<<1, rson=pos<<1|1; tr[lson]= add(mul(tr[lson], laz1[pos]), (laz2[pos]*(len-(len>>1)))%mod); tr[rson]= add(mul(tr[rson], laz1[pos]), (laz2[pos]*(len>>1))%mod); laz1[lson]= mul(laz1[lson], laz1[pos]); laz1[rson]= mul(laz1[rson], laz1[pos]); laz2[lson]= add(mul(laz2[lson], laz1[pos]), laz2[pos]); laz2[rson]= add(mul(laz2[rson], laz1[pos]), laz2[pos]); laz1[pos]=1, laz2[pos]=0; } void update(int flag, int L, int R, int pos, int l, int r, ll c) { if(L<=l && r<=R) { if(flag==1) { laz1[pos]=mul(laz1[pos], c); laz2[pos]=mul(laz2[pos], c); tr[pos]=mul(tr[pos], c); } else { laz2[pos]=add(laz2[pos], c); tr[pos]=add(tr[pos], ((r-l+1)*c)%mod); } return ; } pushdown(pos, r-l+1); int mid=(l+r)>>1; if(L<=mid) update(flag, L, R, pos<<1, l, mid, c); if(mid<R) update(flag, L, R, pos<<1|1, mid+1, r, c); pushup(pos); } ll query(int L, int R, int pos, int l, int r) { if(L<=l && r<=R) return tr[pos]; pushdown(pos, r-l+1); int mid=(l+r)>>1; ll ans=0; if(L<=mid) ans+=query(L, R, pos<<1, l, mid); if(mid<R) ans+=query(L, R, pos<<1|1, mid+1, r); pushup(pos); return ans%mod; } int main() { scanf("%d %lld", &n, &mod); Init(); build(1, 1, n); scanf("%d", &m); int l, r, flag; ll c; rep(i,1,m) { scanf("%d %d %d", &flag, &l, &r); if(flag!=3) { scanf("%lld", &c); update(flag, l, r, 1, 1, n, c); } else { printf("%lld\n", query(l, r, 1, 1, n)); } } return 0; }
D 水,树状数组
题意:n个点,每个点的rank值为x坐标不大于其x坐标,且y坐标不大于其y坐标的点的数量。(不含其自身),求出rank为0~n−1的点的数量。
tags:先对一维坐标排序,然后树状数组维护一下即可。
// D #include<bits/stdc++.h> using namespace std; #pragma comment(linker, "/STACK:102400000,102400000") #define rep(i,a,b) for (int i=a;i<=b;i++) #define per(i,b,a) for (int i=b;i>=a;i--) #define mes(a,b) memset(a,b,sizeof(a)) #define INF 0x3f3f3f3f #define fi first #define se second typedef long long ll; const int N = 100005; int n; ll tr[N], ans[N]; pair<int,int > co[N]; void add(int x, int y) {for(; x<=n; tr[x]+=y, x+=x&-x); } ll sum(int x) {ll ans=0; for(; x>0; ans+=tr[x], x-=x&-x); return ans; } int main() { scanf("%d", &n); rep(i,1,n) scanf("%d %d", &co[i].fi, &co[i].se); sort(co+1, co+1+n); rep(i,1,n) { ++ans[sum(co[i].se)]; add(co[i].se, 1); } rep(i,0,n-1) printf("%lld\n", ans[i]); return 0; }
E 水,树状数组
题意:把一个给定的1~n的排列{a1,a2,…,an}(1≤ai≤n,且ai各不相同),用最少的交换次数,变换成另一个1~n的排列{b1,b2,…,bn}。并且,每次只交换相邻的两个元素。求最小的交换次数。
tags:按b[]的顺序依次计算,直接暴力肯定超时,所以强行搞了个树状数组。。
#include<bits/stdc++.h> using namespace std; #pragma comment(linker, "/STACK:102400000,102400000") #define rep(i,a,b) for (int i=a;i<=b;i++) #define per(i,b,a) for (int i=b;i>=a;i--) #define mes(a,b) memset(a,b,sizeof(a)) #define INF 0x3f3f3f3f typedef long long ll; const int N = 100005; int n, a[N], b[N], id[N], s[N]; ll ans; void add(int x, int c) {for(; x; s[x]+=c, x-=x&-x); } int sum(int x) {int ans=0; for(; x<=n; ans+=s[x], x+=x&-x); return ans; } int main() { scanf("%d", &n); int cnt=0; rep(i,1,n) { scanf("%d", &a[i]); id[a[i]]=i; } rep(i,1,n) { scanf("%d", &b[i]); int id1=id[b[i]], s1=sum(id1); ans+= (id1+s1-i); add(id1, 1); } printf("%lld\n", ans); return 0; }
J 水,优先队列
#include<bits/stdc++.h> using namespace std; #pragma comment(linker, "/STACK:102400000,102400000") #define rep(i,a,b) for (int i=a;i<=b;i++) #define per(i,b,a) for (int i=b;i>=a;i--) #define mes(a,b) memset(a,b,sizeof(a)) #define INF 0x3f3f3f3f typedef long long ll; const int N = 200005; int main() { int n, ai; priority_queue<int , vector<int >, greater<int> > q; scanf("%d", &n); rep(i,1,n) { scanf("%d", &ai); q.push(ai); } int ans=0; rep(i,1,n-1) { int x1=q.top(); q.pop(); int x2=q.top(); q.pop(); ans+= x1+x2, q.push(x1+x2); } printf("%d\n", ans); return 0; }
L 水,食物链原题
#include<iostream> #include<cstdio> #include<cstdlib> #include<algorithm> #include<cstring> #include<string> #include<cmath> #include<queue> #include<stack> #include<map> #include<bitset> #include<vector> #include<set> #include<list> using namespace std; #pragma comment(linker, "/STACK:102400000,102400000") #define rep(i,a,b) for (int i=a;i<=b;i++) #define per(i,b,a) for (int i=b;i>=a;i--) #define mes(a,b) memset(a,b,sizeof(a)) #define INF 0x3f3f3f3f typedef long long ll; const int N = 100005; int n, k, fa[N*3]; int ans[N], ans1; int Find(int x) {return fa[x]==x ? x : fa[x]=Find(fa[x]); } bool same(int a, int b) {return Find(a)==Find(b); } void Unite(int a, int b) { int faa=Find(a), fab=Find(b); if(faa!=fab) fa[faa]=fab; } int main() { scanf("%d %d", &n, &k); rep(i,1,n*3) fa[i]=i; int d, x, y; bool flag=0; rep(ca, 1, k) { scanf("%d %d %d", &d, &x, &y); if(x>n || y>n) { ans[++ans1]=ca; continue; } if(d==1) { if(same(x,y+n) || same(x,y+2*n)) ans[++ans1]=ca; else { Unite(x, y); Unite(x+n, y+n); Unite(x+2*n, y+2*n); } } else { if(x==y || same(x,y) || same(x,y+2*n)) ans[++ans1]=ca; else { Unite(x, y+n); Unite(x+n, y+2*n); Unite(x+2*n, y); } } } rep(i,1,ans1) if(i==1) printf("%d", ans[i]); else printf(" %d", ans[i]); return 0; }
M 题目意思太迷
N 老题了,带正反的并查集
#include<bits/stdc++.h> using namespace std; #pragma comment(linker, "/STACK:102400000,102400000") #define rep(i,a,b) for (int i=a;i<=b;i++) #define per(i,b,a) for (int i=b;i>=a;i--) #define mes(a,b) memset(a,b,sizeof(a)) #define INF 0x3f3f3f3f typedef long long ll; const int N = 2000005; int fa[N]; int Find(int x) {return fa[x]==x ? x : fa[x]=Find(fa[x]); } int main() { int n, m, t, a, b; scanf("%d %d", &n, &m); rep(i,1,n*2) fa[i]=i; rep(i,1,m) { scanf("%d %d %d", &t, &a, &b); int faa1=Find(a*2-1), faa2=Find(a*2), fab1=Find(b*2-1), fab2=Find(b*2); if(t==1) { if(faa1==fab2 || faa2==fab1) {puts("NO"); return 0; } fa[faa1]=fab1, fa[faa2]=fab2; } else { if(faa1==fab1 || faa2==fab2) {puts("NO"); return 0; } fa[faa1]=fab2, fa[faa2]=fab1; } } puts("YES"); return 0; }