zoukankan      html  css  js  c++  java
  • NOIP 2018 简要题解

    从这里开始

      Day 1

      Problem A

        考虑贪心地选取极大非 0 段减少。

        如果两次操作有交,并且不是包含关系,那么把其中一次操作的,但另一次没有操作的移过去,然后就变成了上面那个贪心了。

      Code

      #include <iostream>
      #include <cstdlib>
      #include <cstdio>
      using namespace std;
      typedef bool boolean;
      
      const int N = 1e5 + 5;
      
      int n;
      int res = 0;
      int ar[N];
      
      inline void init() {
      	scanf("%d", &n);
      	for (int i = 1; i <= n; i++)
      		scanf("%d", ar + i);
      }
      
      inline void solve() {
      	int lst = 0;
      	for (int i = 1; i <= n; i++) {
      		if (ar[i] > lst)
      			res += ar[i] - lst;
      		lst = ar[i];
      	}
      	printf("%d
      ", res);
      }
      
      int main() {
      	freopen("road.in", "r", stdin);
      	freopen("road.out", "w", stdout);
      	init();
      	solve();
      	return 0;
      }

      Problem B

        考虑从小到达确定 $b$ 中的面额。不难发现:

      • $b$ 一定是 $a$ 的子集。
      • $a$ 中一种面值不在 $b$ 中当且仅当它能被除掉它之后的面额表示出来。

      Code

      #include <bits/stdc++.h>
      using namespace std;
      typedef bool boolean;
      
      const int N = 105, M = 25005;
      
      int T;
      int n, m;
      int a[N];
      bitset<M> f;
      
      void solve() {
      	scanf("%d", &n);
      	m = 0;
      	for (int i = 1; i <= n; i++) {
      		scanf("%d", a + i);
      		m = max(m, a[i]);
      	}
      	sort(a + 1, a + n + 1);
      	f.reset();
      	f.set(0);
      	int ans = 0;
      	for (int i = 1; i <= n; i++) {
      		if (!f.test(a[i])) {
      			for (int j = a[i]; j <= m; j++) {
      				if (f.test(j - a[i])) {
      					f.set(j);
      				}
      			}
      			ans++;
      		}
      	}
      	printf("%d
      ", ans);
      }
      
      int main() {
      	freopen("money.in", "r", stdin);
      	freopen("money.out", "w", stdout);
      	scanf("%d", &T);
      	while (T--) {
      		solve();
      	}
      	return 0;
      }

      Problem C

        考虑二分答案。考虑在每个子树内决策,每个子树内最多有一条未完成的路径对父节点有贡献。

        首先需要最大化数量,不难证明这样不会更劣。

        首先已经满足条件的可以直接算入答案,没有满足条件考虑两两配对。这个从大的开始考虑,每次和最小的能够匹配的配对。

        考虑如何在数量最大的情况下,最大化对父节点的贡献。考虑最大没有匹配的路径,考虑用它替换掉某组匹配中的较大值。

        时间复杂度 $O(nlog Vlog n)$。

      Code

      #include <algorithm>
      #include <iostream>
      #include <cstdlib>
      #include <cstdio>
      #include <vector>
      using namespace std;
      typedef bool boolean;
      
      template <typename T>
      void pfill(T* pst, const T* ped, T val) {
      	for ( ; pst != ped; *(pst++) = val);
      }
      
      typedef class Edge {
      	public:
      		int ed, nx, w;
      
      		Edge(int ed = 0, int nx = 0, int w = 0):ed(ed), nx(nx), w(w) {	}
      }Edge;
      
      typedef class MapManager {
      	public:
      		int ce;
      		int* h;
      		Edge* es;
      
      		MapManager() : ce(-1), h(NULL), es(NULL) {	}
      		MapManager(int n, int m) : ce(-1) {
      			h = new int[(n + 1)];
      			es = new Edge[(m + 1)];
      			pfill(h, h + n + 1, -1);
      		}	
      
      		void addEdge(int u, int v, int w) {
      			es[++ce] = Edge(v, h[u], w);
      			h[u] = ce;
      		}
      
      		Edge& operator [] (int p) {
      			return es[p];
      		}
      }MapManager;
      
      template <typename T>
      class Pool {
      	public:
      		int sz;
      		T *p;
      		T *tp;
      		
      		Pool(int sz) : sz(sz) {
      			p = new T[sz + 1];
      			tp = p;	
      		}
      
      		void reset() {
      			tp = p;
      		}
      
      		T* alloc(int len) {
      			T* rt = tp;
      			tp += len;
      //			cerr << tp - p << '
      ';
      			return rt;
      		}
      };
      
      typedef pair<int, int> pii;
      
      const int N = 5e4 + 3;
      
      int n, m;
      int deg[N];
      MapManager g;
      Pool<int> pl1(N << 2);
      Pool<pii> pl2(N << 2);
      Pool<boolean> pl3(N << 2);
      
      inline void init() {
      	scanf("%d%d", &n, &m);
      	g = MapManager(n, n << 1);
      	pfill(deg + 1, deg + n + 1, 0);
      	for (int i = 1, u, v, w; i < n; i++) {
      		scanf("%d%d%d", &u, &v, &w);
      		g.addEdge(u, v, w);
      		g.addEdge(v, u, w);
      		deg[u]++, deg[v]++;
      	}
      }
      
      //int cnt;
      pii dfs(int p, int fa, int mid) {
      	int* a = pl1.alloc(deg[p] + 1);
      	pii* m = pl2.alloc(deg[p] + 1);
      	boolean* vis = pl3.alloc(deg[p] + 1);
      //	cerr << ++cnt << '
      ';
      
      	int rt = 0, tp = 0;
      	for (int i = g.h[p], e; ~i; i = g[i].nx) {
      		 if ((e = g[i].ed) == fa)
      			 continue;
      		 pii x = dfs(e, p, mid);
      		 rt += x.first, a[++tp] = (x.second + g[i].w);
      	}
      	
      	sort(a + 1, a + tp + 1);
      	while (tp && a[tp] >= mid)
      		tp--, rt++;
      
      	if (!tp)
      		return pii(rt, 0);
      
      	for (int i = 0; i <= tp; i++)
      		vis[i] = false;
      
      	int l = 1, r = tp, _tp = 0;
      	while (l < r) {
      		while (l < r && a[l] + a[r] < mid)
      			l++;
      		if (l < r) {
      			m[++_tp] = pii(a[l], a[r]);
      			vis[l] = vis[r] = true;
      			l++, r--, rt++;
      		}
      	}
      	
      	while (r && vis[r])
      		r--;
      
      	if (!r)
      		return pii(rt, 0);
      
      	int b = a[r];
      	for (int i = _tp; i; i--)
      		if (m[i].first + b >= mid)
      			return pii(rt, m[i].second);
      	return pii(rt, b);
      }
      
      boolean check(int mid) {
      //	cnt = 0;
      	pl1.reset();
      	pl2.reset();
      	pl3.reset();
      	return dfs(1, 0, mid).first >= m;
      }
      
      inline void solve() {
      	int l = 1, r = 5e8, mid;
      	while (l <= r) {
      		mid = (l + r) >> 1;
      		if (check(mid))
      			l = mid + 1;
      		else
      			r = mid - 1;
      	}
      	printf("%d
      ", l - 1);
      }
      
      int main() {
      	freopen("track.in", "r", stdin);
      	freopen("track.out", "w", stdout);
      	init();
      	solve();
      	return 0;
      }

      Day 2

      Problem A

         暴力枚举断掉环上的哪一条边。

      Code

      #include <algorithm>
      #include <iostream>
      #include <cstdlib>
      #include <cstdio>
      #include <vector>
      #include <stack>
      using namespace std;
      typedef bool boolean;
      
      const int N = 5005;
      
      int n, m;
      int tp;
      int ans[N];
      int cmp[N];
      vector<int> g[N];
      
      inline void init() {
      	scanf("%d%d", &n, &m);
      	for (int i = 1, u, v; i <= m; i++) {
      		scanf("%d%d", &u, &v);
      		g[u].push_back(v);
      		g[v].push_back(u);
      	}
      }
      
      namespace tree {
      
      void dfs(int p, int fa) {
      	ans[++tp] = p;
      	for (int i = 0, e; i < (signed) g[p].size(); i++)
      		if ((e = g[p][i]) ^ fa)
      			dfs(e, p);
      }
      
      inline void solve() {
      	tp = 0;
      	for (int i = 1; i <= n; i++)
      		sort(g[i].begin(), g[i].end());
      	dfs(1, 0);
      	for (int i = 1; i <= n; i++)
      		printf("%d%c", ans[i], (i == n) ? ('
      ') : (' '));
      }
      
      }
      
      namespace circle {
      
      stack<int> s;
      boolean vis[N];
      vector<int> cir;
      
      boolean dfs1(int p, int fa) {
      	if (vis[p]) {
      		int cur;
      		do {
      			cur = s.top();
      			s.pop();
      			cir.push_back(cur);
      		} while (cur != p);
      		return true;
      	}
      	s.push(p), vis[p] = true;
      	for (int i = 0, e; i < (signed) g[p].size(); i++)
      		if (((e = g[p][i]) ^ fa) && dfs1(e, p))
      			return true;
      	s.pop();
      	return false;
      }
      
      void dfs(int p, int fa, int banu, int banv) {
      	cmp[++tp] = p;
      //	cerr << p << " " << tp << '
      ';
      	boolean sgn1 = (p == banu || p == banv);
      	for (int i = 0, e; i < (signed) g[p].size(); i++) {
      		e = g[p][i];
      		if ((e ^ fa) && !(sgn1 && (e == banu || e == banv)))
      			dfs(e, p, banu, banv);
      	}
      }
      
      boolean check_update() {
      	for (int i = 1; i <= n; i++)
      		if (ans[i] ^ cmp[i])
      			return cmp[i] < ans[i];
      	return false;
      }
      
      inline void solve() {
      	for (int i = 1; i <= n; i++)
      		sort(g[i].begin(), g[i].end());
      	dfs1(1, 0);
      	signed int s = (signed) cir.size();
      	tp = 0;
      	dfs(1, 0, cir[0], cir[1]);
      	for (int j = 1; j <= n; j++)
      		ans[j] = cmp[j];
      	for (int i = 1; i < s; i++) {
      //		cerr << cir[i] << '
      ';
      		tp = 0;
      		dfs(1, 0, cir[i], cir[(i + 1) % s]);
      		if (check_update())
      			for (int j = 1; j <= n; j++)
      				ans[j] = cmp[j];
      	}
      	for (int i = 1; i <= n; i++)
      		printf("%d%c", ans[i], (i == n) ? ('
      ') : (' '));
      }
      
      }
      
      int main() {
      	freopen("travel.in", "r", stdin);
      	freopen("travel.out", "w", stdout);
      	init();
      	if (n == m)
      		circle :: solve();
      	else
      		tree :: solve();
      	return 0;
      }
      

        好像校内 oj 上测,最慢一个点 978ms,Emm......

        其实考虑在环上每一个位置往回走的下一个标号是确定的。然后就能 $O(nlog n)$ 了。

        最近手残得比较厉害,sad.....

      Code

      #include <bits/stdc++.h>
      using namespace std;
      typedef bool boolean;
      
      const int N = 5e3 + 5;
      
      int n, m;
      vector<int> ans;
      vector<int> G[N];
      
      void dfs(int p, int fa, vector<int> &ans = ::ans) {
      	ans.push_back(p);
      	for (int _ = 0, e; _ < (signed) G[p].size(); _++) {
      		if ((e = G[p][_]) ^ fa) {
      			dfs(e, p);
      		}
      	}
      } 
      
      boolean vis[N];
      vector<int> cir;
      boolean findcir(int p, int fa) {
      	if (vis[p]) {
      		vector<int>::iterator it = --cir.end();
      		while (*it ^ p)
      			it--;
      		cir.erase(cir.begin(), it);
      		return true;
      	}
      	vis[p] = true;
      	cir.push_back(p);
      	for (int _ = 0, e; _ < (signed) G[p].size(); _++) {
      		if (((e = G[p][_]) ^ fa) && findcir(e, p)) {
      			return true;
      		}
      	}
      	cir.pop_back();
      	return false;
      }
      
      void finderase(vector<int>& a, int x) {
      	vector<int>::iterator it = a.begin();
      	while (*it ^ x)
      		it++;
      	a.erase(it);
      }
      
      int main() {
      	freopen("travel.in", "r", stdin);
      	freopen("travel.out", "w", stdout);
      	scanf("%d%d", &n, &m);
      	for (int i = 1, u, v; i <= m; i++) {
      		scanf("%d%d", &u, &v);
      		G[u].push_back(v);
      		G[v].push_back(u);
      	}
      	for (int i = 1; i <= n; i++)
      		sort(G[i].begin(), G[i].end());
      	if (n == m) {
      		findcir(1, 0);
      		int nxt = *upper_bound(G[cir[0]].begin(), G[cir[0]].end(), cir[1]);
      		for (int i = 1, x, y; ; i++) {
      			x = cir[i];
      			if (x >= nxt) {
      				y = cir[i - 1];
      				finderase(G[x], y);
      				finderase(G[y], x);
      //				cerr << x << " " << y << " " << nxt << '
      ';
      				break;
      			}
      			vector<int>::iterator it = upper_bound(G[x].begin(), G[x].end(), cir[i + 1]);
      			if (it != G[x].end() && *it == cir[i - 1])
      				it++;
      			if (it != G[x].end())
      				nxt = *it;
      		}
      	} 
      	dfs(1, 0, ans);
      	for (int i = 0; i < n; i++)
      		printf("%d ", ans[i]);
      	return 0;
      }

      Problem B

        请欣赏神仙行为:

      • 早上教练发题,神仙 jerome_wei 说难道这题能做,下午发成绩,rk 1 cdqz-wyp 100 100 100 300
      • 早上教练发题,神仙 jerome_wei 说咕了咕了,下午发成绩,rk 1 cdqz-wyp 100 100 100 300
      • 一天,神仙  jerome_wei 看到了这道题,说这什么鬼题,跑了跑了,不久之后博客上出现了详细题解和证明

         不难发现 $a_{x, y} geqslant a_{x - 1, y + 1}$。

        考虑一处不合法的路径,如果存在一定是字典序相邻的一对,这样话就是考虑把最后一个不在最后一行的 R 替换成 D,大概是这样的:

        你发现如果第二个位置相等,由于在另一条路径下方的权值一定是小于等于它的,由此可以推出它们字典序相等。那么右下角的大矩形内每一对 $x + y$ 相等的 $a_{x, y}$ 都是相同的。

        随便 dp 一下应该能拿到 65 分的好成绩。(枚举 $x + y$ 的值,状压一下当前的满足 $a_{x, y} = a_{x - 1, y + 1}$ 以及横纵坐标和等于 $x + y + 1$ 的状态)

        不难注意到,当 $m$ 比较大的时候,中间的有效状态只有常数个,考虑 $x = 0, 1$ 总是可行的,当 $x geqslant 3, y geqslant 2$ 的时候,这些格子必须满足 $a_{x, y} = a_{x - 1, y + 1}$。因为:

        因为红格子和蓝格子以及蓝格子和黄格子不可能同时都不同。

        理论上中间暴力 dp 能过,不过写个矩乘快速幂怎么都能过,我好像有地方写菜了,然后好像就过不了?因为我非常地懒,众所周知,打表可得当 $m geqslant n + 1$ 的时候当 $m$ 每增加 1,答案乘上 3。

        如果我 csp 后没退役再来填这个规律的坑好了。

      Code

      #include <bits/stdc++.h>
      using namespace std;
      typedef bool boolean;
      
      #define ll long long
      
      void exgcd(int a, int b, int& x, int& y) {
      	if (!b) {
      		x = 1, y = 0;
      	} else {
      		exgcd(b, a % b, y, x);
      		y -= (a / b) * x;
      	}
      }
      
      int inv(int a, int n) {
      	int x, y;
      	exgcd(a, n, x, y);
      	return (x < 0) ? (x + n) : (x);
      }
      
      const int Mod = 1e9 + 7;
      
      template <const int Mod = :: Mod>
      class Z {
      	public:
      		int v;
      
      		Z() : v(0) {	}
      		Z(int x) : v(x){	}
      		Z(ll x) : v(x % Mod) {	}
      
      		friend Z operator + (const Z& a, const Z& b) {
      			int x;
      			return Z(((x = a.v + b.v) >= Mod) ? (x - Mod) : (x));
      		}
      		friend Z operator - (const Z& a, const Z& b) {
      			int x;
      			return Z(((x = a.v - b.v) < 0) ? (x + Mod) : (x));
      		}
      		friend Z operator * (const Z& a, const Z& b) {
      			return Z(a.v * 1ll * b.v);
      		}
      		friend Z operator ~(const Z& a) {
      			return inv(a.v, Mod);
      		}
      		friend Z operator - (const Z& a) {
      			return Z(0) - a;
      		}
      		Z& operator += (Z b) {
      			return *this = *this + b;
      		}
      		Z& operator -= (Z b) {
      			return *this = *this - b;
      		}
      		Z& operator *= (Z b) {
      			return *this = *this * b;
      		}
      		friend boolean operator == (const Z& a, const Z& b) {
      			return a.v == b.v;
      		} 
      };
      
      Z<> qpow(Z<> a, int p) {
      	Z<> rt = Z<>(1), pa = a;
      	for ( ; p; p >>= 1, pa = pa * pa) {
      		if (p & 1) {
      			rt = rt * pa;
      		}
      	}
      	return rt;
      }
      
      typedef Z<> Zi;
      
      #define pii pair<int, int>
      
      const int N = 1e6 + 10;
      
      int n, m;
      int Lx[N], Rx[N];
      map<pii, Zi> G[N];
      
      int opt(int sum, int s, int x) {
      	if (x <= Lx[sum] || x > Rx[sum])
      		return s;
      	return s | (1 << x);
      }
      
      Zi dp(int sum, int s0, int s1) {
      	if (sum == n + m - 2)
      		return 2;
      	if (G[sum].count(pii(s0, s1))) {
      		return G[sum][pii(s0, s1)];
      	}
      	Zi rt = 0;
      	int ns0 = s1;
      	for (int i = Lx[sum]; i <= Rx[sum]; i++) {
      		if ((s0 >> i) & 1) {
      			ns0 = opt(sum + 1, ns0, i);
      			ns0 = opt(sum + 1, ns0, i + 1);
      		}
      	}
      	for (int i = Lx[sum]; i <= Rx[sum] + 1; i++) {
      		if ((s0 >> i) & 1)
      			continue;
      		int ns1 = 0;
      		for (int j = Lx[sum] + 1; j <= i && j <= Rx[sum]; j++)
      			ns1 = opt(sum + 2, ns1, j + 1);
      		for (int j = i + 2; j <= Rx[sum]; j++)
      			ns1 = opt(sum + 2, ns1, j + 1);
      		rt += dp(sum + 1, ns0, ns1);
      	}
      //	cerr << sum << " " << s0 << " " << s1 << " " << rt.v << '
      ';
      	return G[sum][pii(s0, s1)] = rt;
      }
      
      Zi solve(int n, int m) {
      	if (n > m)
      		swap(n, m);
      	if (n == m || m == n + 1) {
      		::n = n, ::m = m;
      		for (int i = 0; i < m + 10; i++) {
      			Lx[i] = 20, Rx[i] = 0;
      		}
      		for (int i = 0; i < n; i++) {
      			for (int j = 0; j < m; j++) {
      				Lx[i + j] = min(Lx[i + j], i);
      				Rx[i + j] = max(Rx[i + j], i);
      			}
      		}
      		return dp(0, 0, 0);
      	}
      	if (n == 1)
      		return qpow(2, m);
      	return solve(n, n + 1) * qpow(3, m - n - 1);
      }
      
      int main() {
      	freopen("game.in", "r", stdin);
      	freopen("game.out", "w", stdout);
      	scanf("%d%d", &n, &m);
      	printf("%d
      ", solve(n, m).v);
      	return 0;
      }

      Problem C

        ddp 板题。

        考察选手能否熟练地敲打 ddp 板子。

      Code

      #include <bits/stdc++.h>
      using namespace std;
      typedef bool boolean;
      
      const int N = 1e5 + 5;
      
      #define ll long long
      
      template <typename T>
      T smin(T a, T b) {
      	return min(a, b);
      }
      template <typename T, typename ...Q>
      T smin(T a, const Q &...args) {
      	return min(a, smin(args...));
      }
      
      const ll llf = 1e12;
      
      typedef class Data {
      	public:
      		ll a[2][2];
      
      		Data() {	}
      		Data(ll x) {
      			a[0][0] = llf, a[0][1] = 0;
      			a[1][0] = x, a[1][1] = x;
      		}
      		Data(ll x, ll y, ll z, ll w) {
      			a[0][0] = x, a[0][1] = y;
      			a[1][0] = z, a[1][1] = w;
      		}
      
      		Data get() {
      			ll g = min(a[0][0], a[0][1]);
      			ll f = min(a[1][0], a[1][1]);
      			g = min(g, f);
      			return Data(f, f, g, g);
      		}
      		ll* operator [] (int p) {
      			return a[p];
      		}
      		friend Data operator * (Data a, Data b) {
      			Data rt;
      			rt[0][0] = min(a[0][0] + b[0][0], a[0][1] + b[1][0]);
      			rt[0][1] = min(a[0][0] + b[0][1], a[0][1] + b[1][1]);
      			rt[1][0] = min(a[1][0] + b[0][0], a[1][1] + b[1][0]);
      			rt[1][1] = min(a[1][0] + b[0][1], a[1][1] + b[1][1]);
      			return rt;
      		}
      		friend Data operator + (Data a, Data b) {
      			Data rt;
      			rt[0][0] = a[0][0] + b[0][0];
      			rt[0][1] = a[0][1] + b[0][1];
      			rt[1][0] = a[1][0] + b[1][0];
      			rt[1][1] = a[1][1] + b[1][1];
      			return rt;
      		}
      		friend Data operator - (Data a, Data b) {
      			Data rt;
      			rt[0][0] = a[0][0] - b[0][0];
      			rt[0][1] = a[0][1] - b[0][1];
      			rt[1][0] = a[1][0] - b[1][0];
      			rt[1][1] = a[1][1] - b[1][1];
      			return rt;
      		}
      		ll get_ans() {
      			ll rt = smin(a[0][0], a[0][1], a[1][0], a[1][1]);
      			return (rt >= llf) ? (-1) : (rt);
      		}
      } Data;
      
      typedef class SegTreeNode {
      	public:
      		Data d;
      		SegTreeNode *fa;
      		SegTreeNode *l, *r;
      
      		void push_up() {
      			d = l->d * r->d;
      		}
      } SegTreeNode;
      
      typedef class Chain {
      	public:
      		SegTreeNode *st;
      		int len, top;
      
      		Chain() {	}
      		Chain(int top);
      
      		void update(int, Data, Data);
      } Chain;
      
      SegTreeNode pool[N << 1];
      SegTreeNode *_top = pool;
      
      int S[N];
      Data dat[N];
      
      int tp;
      Chain *ch[N];
      SegTreeNode *tr[N];
      
      void build(SegTreeNode*& p, int l, int r) {
      	p = _top++;
      	if (l == r) {
      		p->d = dat[S[l]];
      		tr[S[l]] = p;
      		return;
      	}
      	int mid = (l + r) >> 1;
      	build(p->l, l, mid);
      	build(p->r, mid + 1, r);
      	p->push_up();
      	p->l->fa = p;
      	p->r->fa = p;
      }
      
      Chain::Chain(int top) : st(_top), len(tp), top(top) {
      	reverse(S + 1, S + tp + 1);
      	build(st, 1, len);
      	for (int i = 1; i <= len; i++) {
      		ch[S[i]] = this;
      	} 
      	if (top) {
      		dat[top] = dat[top] + st->d.get();
      	}
      }
      
      void Chain::update(int x, Data old_d, Data new_d) {
      	Data nold_d = st->d.get();
      	tr[x]->d = tr[x]->d - old_d + new_d;
      	for (SegTreeNode *p = tr[x]->fa; p; p = p->fa)
      		p->push_up();
      	if (top) {
      		ch[top]->update(top, nold_d, st->d.get());
      	}
      }
      
      int n, m;
      int p[N];
      int sz[N], zson[N];
      vector<int> G[N];
      
      void dfs1(int p, int fa) {
      	int mx = 0, &id = zson[p];
      	sz[p] = 1;
      	for (auto e : G[p]) {
      		if (e ^ fa) {
      			dfs1(e, p);
      			sz[p] += sz[e];
      			if (mx < sz[e]) {
      				mx = sz[e];
      				id = e;
      			}
      		}
      	}
      }
      
      void dfs2(int p, int fa) {
      	if (zson[p]) {
      		for (auto e : G[p]) {
      			if ((e ^ fa) && (e ^ zson[p])) {
      				dfs2(e, p);
      				new Chain(p);
      			}
      		}
      		dfs2(zson[p], p);
      	} else {
      		tp = 0;
      	}
      	S[++tp] = p;
      }
      
      int main() {
      	freopen("defense.in", "r", stdin);
      	freopen("defense.out", "w", stdout);
      	scanf("%d%d%*s", &n, &m);
      	for (int i = 1, x; i <= n; i++) {
      		scanf("%d", &x);
      		dat[i] = x;
      		p[i] = x;
      	}
      	for (int i = 1, u, v; i < n; i++) {
      		scanf("%d%d", &u, &v);
      		G[u].push_back(v);
      		G[v].push_back(u);
      	}
      	dfs1(1, 0);
      	dfs2(1, 0);
      	new Chain(0);
      	int a, x, b, y;
      	while (m--) {
      		scanf("%d%d%d%d", &a, &x, &b, &y);
      		Data olda = p[a], oldb = p[b];
      		Data na = Data(llf * (1 - x)), nb = Data(llf * (1 - y));
      		ch[a]->update(a, olda, na);
      		ch[b]->update(b, oldb, nb);
      		ll ans = ch[1]->st->d.get_ans() + olda[1][0] * x + oldb[1][0] * y;
      		ch[a]->update(a, na, olda);
      		ch[b]->update(b, nb, oldb);
      		printf("%lld
      ", ans);
      	}
      	return 0;
      } 

    • 相关阅读:
      转载---JVM四种引用--用于记录知识
      Ionic的安装、创建、及一些记录
      Angular响应式表单--附上完整代码演示
      Angular自定义模块—使用路由实现懒加载--及错误解决
      Angular自定义模块(普通)
      Angula获取服务器数据
      Angular同步与异步获取服务数据(附完整代码)
      Angular父子组件的方法传递以及数据传递
      logrotate
      Capistrano 3
    • 原文地址:https://www.cnblogs.com/yyf0309/p/11849139.html
    Copyright © 2011-2022 走看看