n<=10,直接搜索选了那些点便可。ios
复杂度$O(2^n)$,指望得分20分。git
数据是一条链。数组
那么条件转化为:选了一个点后,它后面中全部的点的权值比他大。ide
那么求一遍最长上升子序列便可。优化
复杂度$O(nlogn)$。spa
根据sol2的作法,若是将树转化为dfs序,那么就和sol3的作法同样了。code
注意dfs的过程当中,先遍历右节点,而后左节点。blog
复杂度$O(nlogn)$,指望得分100分。get
#include<cstdio> #include<algorithm> #include<cstring> #include<iostream> #include<cctype> using namespace std; inline int read() { int x = 0, f = 1; char ch = getchar(); for (; !isdigit(ch); ch = getchar())if (ch == '-')f = -1; for (; isdigit(ch); ch = getchar())x = x * 10 + ch - '0'; return x * f; } const int N = 100005; int w[N], ls[N], rs[N], q[N], f[N], tot; void dfs(int u) { if (!u) return ; q[++tot] = u; dfs(rs[u]); dfs(ls[u]); } int main() { freopen("point.in", "r", stdin); freopen("point.out", "w", stdout); int n = read(); for (int i = 1; i <= n; ++i) w[i] = read(); for (int i = 1; i <= n; ++i) ls[i] = read(), rs[i] = read(); dfs(1); for (int i = 1; i <= n; ++i) q[i] = w[q[i]]; int cnt = 1; f[1] = q[1]; for (int i = 2; i <= n; ++i) { if (q[i] > f[cnt]) f[++cnt] = q[i]; else { int pos = lower_bound(f + 1, f + cnt + 1, q[i]) - f; f[pos] = q[i]; } } cout << cnt; return 0; }
动态开点线段树直接模拟string
会T,毕竟常数巨大
// 这个代码写的有点zz啊 #include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include <string> using namespace std; #define Rep(i, a, b) for(register int i = a; i <= b; i ++) #define getchar() (p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1<<22, stdin), p1 == p2) ? EOF : *p1++) char buf[(1 << 22)], *p1 = buf, *p2 = buf; #define gc getchar() inline int read() { int x = 0, f = 1; char c = gc; while(c < '0' || c > '9') {if(c == '-') f = -1; c = gc;} while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = gc; return x * f; } #define LL long long const int N = 1e5 + 5; int data[N * 32], Root[N * 32], Lson[N * 32], Rson[N * 32]; int n; int jd; struct Node { int x, y; } ask[N]; int Max; int Poi_A(int l, int r, int &rt, int x) { if(!rt) rt = ++ jd; if(l == r) { if(!data[rt]) { data[rt] = l; return l; } else { return data[rt]; } } int mid = (l + r) >> 1; if(x <= mid) return Poi_A(l, mid, Lson[rt], x); else return Poi_A(mid + 1, r, Rson[rt], x); } void Poi_G(int l, int r, int rt, int x, int num) { if(!rt) return ; if(l == r) { data[rt] = num; return ; } int mid = (l + r) >> 1; if(x <= mid) Poi_G(l, mid, Lson[rt], x, num); else Poi_G(mid + 1, r, Rson[rt], x, num); } struct Node1 { int num, w; } G[N * 3]; int tot; void Dfs(int l, int r, int rt) { if(!rt) return ; if(l == r) { G[++ tot].num = data[rt]; G[tot].w = l; return ; } int mid = (l + r) >> 1; Dfs(l, mid, Lson[rt]); Dfs(mid + 1, r, Rson[rt]); } int Imp; void Sec_A(int l, int r, int rt, int x, int y) { if(!rt) return ; if(x <= l && r <= y) { Imp += data[rt]; return ; } if(l == r) return ; int mid = (l + r) >> 1; if(x <= mid) Sec_A(l, mid, Lson[rt], x, y); if(y > mid) Sec_A(mid + 1, r, Rson[rt], x, y); } void Poi_Mod(int l, int r, int &rt, int x) { if(!rt) rt = ++ jd; data[rt] ++; if(l == r) return ; int mid = (l + r) >> 1; if(x <= mid) Poi_Mod(l, mid, Lson[rt], x); else Poi_Mod(mid + 1, r, Rson[rt], x); } int tdata[N * 32], tRoot[N * 32], tLson[N * 32], tRson[N * 32]; int tjd; void tSec_A(int l, int r, int rt, int x, int y) { if(!rt) return ; if(x <= l && r <= y) { Imp += tdata[rt]; return ; } if(l == r) return ; int mid = (l + r) >> 1; if(x <= mid) tSec_A(l, mid, tLson[rt], x, y); if(y > mid) tSec_A(mid + 1, r, tRson[rt], x, y); } void tPoi_Mod(int l, int r, int &rt, int x) { if(!rt) rt = ++ tjd; tdata[rt] ++; if(l == r) return ; int mid = (l + r) >> 1; if(x <= mid) tPoi_Mod(l, mid, tLson[rt], x); else tPoi_Mod(mid + 1, r, tRson[rt], x); } int main() { freopen("a.in", "r", stdin); freopen("a.out", "w", stdout); n = read(); Rep(i, 1, n) { int x = read(), y = read(); if(x > y) swap(x, y); ask[i].x = x, ask[i].y = y; Max = max(Max, ask[i].y); } Rep(i, 1, n) { int x = Poi_A(1, Max, Root[1], ask[i].x); int y = Poi_A(1, Max, Root[1], ask[i].y); Poi_G(1, Max, Root[1], ask[i].x, y); Poi_G(1, Max, Root[1], ask[i].y, x); } Dfs(1, Max, Root[1]); memset(Root, 0, sizeof Root); memset(Lson, 0, sizeof Lson); memset(Rson, 0, sizeof Rson); memset(data, 0, sizeof data); jd = 0; LL Answer = 0; Rep(i, 1, tot) { tPoi_Mod(1, Max, tRoot[1], G[i].w); } Rep(i, 1, tot) { int x = G[i].num, w = G[i].w; Imp = 0; Sec_A(1, Max, Root[1], x + 1, Max); Answer += Imp; int l, r; if(abs(x - w) < 2) { Poi_Mod(1, Max, Root[1], x); continue; } if(x > w) { l = w + 1, r = x - 1; Imp = 0; tSec_A(1, Max, tRoot[1], l, r); Answer += (r - l + 1 - Imp); } else { l = x + 1, r = w - 1; Imp = 0; tSec_A(1, Max, tRoot[1], l, r); Answer += (r - l + 1 - Imp); } Poi_Mod(1, Max, Root[1], x); } cout << Answer; return 0; }
#include<cstdio> #include<algorithm> #include<stack> #include<queue> #include<cmath> #include <iostream> #define LL long long #define lb(x) (x & (-x)) #define Pair pair<int, int> #define fi first #define se second #define MP(x, y) make_pair(x, y) using namespace std; const int MAXN = 1e6 + 10; inline int read() { char c = getchar(); int x = 0, f = 1; while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();} while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar(); return x * f; } int N; int T[MAXN], date[MAXN], pos[MAXN]; LL sum[MAXN]; // val[i] i位置的元素 // date 离散化数组 Pair P[MAXN]; void add(int x) { for(int i = x; i <= N * 2; i += lb(i)) T[i]++; } LL Query(int x) { LL ans = 0; for(int i = x; i; i -= lb(i)) ans += T[i]; return ans; } int main() { N = read(); for(int i = 1; i <= N; i++) { P[i].fi = read(), P[i].se = read(); date[i] = P[i].fi; date[i + N] = P[i].se; pos[i] = i; pos[i + N] = i + N; } sort(date + 1, date + N * 2 + 1); int num = unique(date + 1, date + N * 2 + 1) - date - 1; for(int i = 1; i <= num; i++) sum[i] = sum[i - 1] + date[i] - date[i - 1] - 1; for(int i = 1; i <= N; i++) { P[i].fi = lower_bound(date + 1, date + num + 1, P[i].fi) - date; P[i].se = lower_bound(date + 1, date + num + 1, P[i].se) - date; swap(pos[P[i].fi], pos[P[i].se]); } LL ans = 0; for(int i = num; i >= 1; i--) { ans += Query(pos[i]); ans += abs(sum[pos[i]] - sum[i]); add(pos[i]); } std:: cout << ans; return 0; }
这道题目考察的是一点思路加上树上的一些性质。
能够说是vector加上启发式合并的一道题目吧。
思路抄袭借鉴于[HNOI2009]梦幻布丁(好吧我只是把它搬到了树上)
题目意思是在树上统计同色联通快个数,更改颜色。
30pts:
咱们发现给定咱们树上的全部节点的颜色,咱们能够O(n)求得军团个数,方法是进行dfs,若是一个结点和他父亲节点颜色不一样,答案就++
而后暴力更改暴力统计答案
30pts2:
咱们能够优化一下上面那个暴力,用vector纪录下每种颜色存在的位置,而后枚举要更改的颜色位置,每一个位置原来对于答案的贡献是和他相邻不一样色的节点个数,咱们减去原来的答案加上更改后的答案就获得了当前的答案。而后再暴力合并vector就好了。
20pts:是一条链,就是梦幻布丁那道题,再也不细说了
100pts: 咱们考虑优化合并操做,咱们发现把x变成y和把y变成x获得的答案是相同的,因此咱们在合并的时候以及更改颜色的时候都是把颜色少的改为颜色多的,而且维护每种颜色实际的vector是哪一个,而后就至关于启发式合并。
每一个点的复杂度是他的度数乘以它被统计答案的次数,最差状况下每一个点也只会被统计logN次答案,那么复杂度就是logN * \sum 度数 等于2NlogN
#include<cstdio> #include<algorithm> #include<cstring> #include<queue> #include<iostream> #include<ctime> #include<cmath> #include<set> #include<map> #define ll long long #define M 200010 using namespace std; int read() { int nm = 0, f = 1; char c = getchar(); for(; !isdigit(c); c = getchar()) if(c == '-') f = -1; for(; isdigit(c); c = getchar()) nm = nm * 10 + c - '0'; return nm * f; } int note[M], sz[M], cor[M], id[M]; vector<int>to[M], to1[M]; int n, q, ans; void dfs(int now, int fa) { if(cor[now] != 0 && cor[now] != cor[fa]) ans++; for(int i = 0; i < to[now].size(); i++) { int vj = to[now][i]; if(vj == fa) continue; dfs(vj, now); } } void del(int x) { for(int i = 0; i < to[x].size(); i++) { int vj = to[x][i]; if(cor[vj] != cor[x]) ans--; } } void insert(int x) { for(int i = 0; i < to[x].size(); i++) { int vj = to[x][i]; if(cor[vj] != cor[x]) ans++; } } int tot = 0, tot2 = 0; int main() { n = read(), q = read(); for(int i = 1; i <= n; i++) cor[i] = read(), sz[cor[i]]++, to1[cor[i]].push_back(i), id[i] = i, note[i] = i; for(int i = 1; i < n; i++) { int vi = read(), vj = read(); to[vi].push_back(vj), to[vj].push_back(vi); } to[1].push_back(0), cor[0] = 0x3e3e3e3e; dfs(1, 0); while(q--) { int x = read(), y = read(); int xn = id[x], yn = id[y]; if(sz[xn] < sz[yn]) { tot += sz[xn], tot2 += to1[xn].size(); for(int i = 0; i < to1[xn].size(); i++) { int op = to1[xn][i]; del(op); to1[yn].push_back(op); } for(int i = 0; i < to1[xn].size(); i++) { int op = to1[xn][i]; cor[op] = yn; } for(int i = 0; i < to1[xn].size(); i++) { int op = to1[xn][i]; insert(op); } to1[xn].clear(); sz[yn] += sz[xn]; sz[xn] = 0; id[x] = 0; } else { tot+=sz[yn], tot2 += to1[yn].size(); for(int i = 0; i < to1[yn].size(); i++) { int op = to1[yn][i]; del(op); to1[xn].push_back(op); } for(int i = 0; i < to1[yn].size(); i++) { int op = to1[yn][i]; cor[op] = xn; } for(int i = 0; i < to1[yn].size(); i++) { int op = to1[yn][i]; insert(op); } to1[yn].clear(); sz[xn] += sz[yn]; sz[yn] = 0; id[y] = xn; id[x] = 0; } cout << ans << "\n"; } return 0; }