zoukankan      html  css  js  c++  java
  • HGOI 20200725

    又是自闭的一天

    T1 首都(capital)

    换根dp

    首先以1为根搜出所有的反边

    然后dp

    (dp)(i) 时,(i) 的父亲已经知道答案

    只需考虑 ((fa,i)) 这条边

    正为 (+1),反为 (-1)

    #include <bits/stdc++.h>
    using namespace std;
    
    #define rep(i, a, b) for (int i = a; i <= b; i++)
    #define per(i, a, b) for (int i = a; i >= b; i--)
    #define siz(a) (int)a.size()
    #define pb push_back
    #define mp make_pair
    #define ll long long
    #define fi first
    #define se second
    
    const int N = 200010 ;
    
    int n, ans ;
    int val[N], res[N] ;
    vector <pair<int, int> > e[N] ;
    
    void dfs1(int u, int ft) {
    	rep(i, 0, siz(e[u]) - 1) {
    		int v = e[u][i].fi ;
    		if (v == ft) continue ;
    		dfs1(v, u) ;
    		val[u] += val[v] + e[u][i].se ;
    	}
    }
    
    void dfs2(int u, int ft, int v1, int v2) {
    	res[u] = val[1] - v1 + v2 ;
    	ans = min(ans, res[u]) ;
    	rep(i, 0, siz(e[u]) - 1) {
    		int v = e[u][i].fi ;
    		if (v == ft) continue ;
    		if (e[u][i].se) dfs2(v, u, v1 + 1, v2) ;
    		else dfs2(v, u, v1, v2 + 1) ;
    	}
    }
    
    signed main() {
    	scanf("%d", &n) ;
    	rep(i, 1, n - 1) {
    		int u, v ; scanf("%d%d", &u, &v) ;
    		e[u].pb(mp(v, 0)) ;
    		e[v].pb(mp(u, 1)) ;
    	}
    	ans = 2 * n ;
    	dfs1(1, 0) ;
    	dfs2(1, 0, 0, 0) ;
    	printf("%d
    ", ans) ;
    	rep(i, 1, n) if (res[i] == ans) printf("%d ", i) ;
    
    	return 0 ;
    }
    
    

    T2 maxmin

    这个题有点意思

    题意是查所有子区间 ([i,j](i<j)) 中最大值-最小值 在 ([l,r]) 范围内的个数

    (n*q<=2*10^6) 提示我们是 (O(nq))

    首先预处理 ((l,r)) 的区间中最小值和最大值

    ([l,r]) 的个数 = 在 ([0,r]) 的个数-在 ([0,l-1]) 的个数

    然后考虑 (two-pointers)

    对于一个 (l) 我们求出他最大的满足的 (r)

    算两次

    就可以了

    其实可以用单调队列,有点类似滑动窗口

    可以AC

    #include <bits/stdc++.h>
    using namespace std;
    
    #define rep(i, a, b) for (int i = a; i <= b; i++)
    #define per(i, a, b) for (int i = a; i >= b; i--)
    #define siz(a) (int)a.size()
    #define pb push_back
    #define mp make_pair
    #define ll long long
    #define fi first
    #define se second
    
    const int N = 500010 ;
    
    int n, q ;
    int mx[N][25], mi[N][25], a[N], ans1[N], ans2[N] ;
    
    void build() {
    	rep(i, 1, n) mx[i][0] = mi[i][0] = a[i] ;
    	rep(j, 1, 20) 
    	rep(i, 1, n - (1 <<j) + 1) {
    		mx[i][j] = max(mx[i][j - 1], mx[i + (1 << (j - 1))][j - 1]) ;
    		mi[i][j] = min(mi[i][j - 1], mi[i + (1 << (j - 1))][j - 1]) ;
        }
    }
    
    int query(int x, int y) {
    	if (x > y) swap(x, y) ;
    	int k = (double) log(y - x + 1) / log(2.0) ; 
    	return max(mx[x][k], mx[y - (1 << k) + 1][k]) - min(mi[x][k], mi[y - (1 << k) + 1][k]) ;
    }
    
    ll solve(int L, int R) {
        ll ans = 0 ;
        for (int i = 1, r = 1; i <= n; i++) {
        	while (r + 1 <= n && query(i, r + 1) < L) r++ ;
        	ans1[i] = r ;
    	}
    	for (int i = 1, r = 1; i <= n; i++) {
    		while (r + 1 <= n && query(i, r + 1) <= R) r++ ;
    		ans2[i] = r ;
    	}
    	rep(i, 1, n) if (ans1[i] <= ans2[i]) ans += ans2[i] - ans1[i] ;
    	return ans ;
    }
    
    signed main() {
    	scanf("%d%d", &n, &q) ;
    	rep(i, 1, n) scanf("%d", &a[i]) ;
    	build() ;
    	while (q--) {
    		int l, r ; scanf("%d%d", &l, &r) ;
    		printf("%lld
    ", solve(l, r)) ;
    	}
    	return 0 ;
    }
    
    

    T3 简单数论题(number)

    出题人你有毒吧

    直接放板子题,然后 (n)(10^18)

    洛谷模板的第一个问题

    代码就不放了

  • 相关阅读:
    洛谷 P1219 八皇后【经典DFS,温习搜索】
    洛谷 P1972 [SDOI2009]HH的项链【莫队算法学习】
    hihoCoder #1015 : KMP算法【KMP裸题,板子】
    UVa 10341
    UVa 11461
    Uva
    BZOJ 3097: Hash Killer I【构造题,思维题】
    BZOJ 1207: [HNOI2004]打鼹鼠【妥妥的n^2爆搜,dp】
    BZOJ 1800: [Ahoi2009]fly 飞行棋【思维题,n^4大暴力】
    新版百度指数2013-12-23正式上线
  • 原文地址:https://www.cnblogs.com/harryhqg/p/13376726.html
Copyright © 2011-2022 走看看