zoukankan      html  css  js  c++  java
  • 2017省选集训测试赛(二十五)Problem B recollection

    @(XSY)[后缀数组, 启发式合并, ST表]

    Description

    Description
    Description

    Solution

    后缀数组 + 启发式合并 + Sparse Table.
    这是第一次写树上后缀数组.
    对以每个点为根的子树统计答案, 用一个set来维护子树下每个点节点在的排名, 启发式合并一颗子树的信息和当前节点的信息.
    一些边界情况需要注意.

    #include <cstdio>
    #include <cctype>
    #include <cstring>
    #include <vector>
    #include <algorithm>
    #include <set>
    #include <cmath>
    
    const int N = 1 << 18, MOD = 998244353, K = 47;
    int n;
    
    inline int modPower(int a, int x)
    {
    	int res = 1;
    
    	for(; x; a = (long long)a * a % MOD, x >>= 1)
    		if(x & 1)
    			res = (long long)res * a % MOD;
    
    	return res;
    }
    
    namespace Zeonfai
    {
    	inline int getInt()
    	{
    		int a = 0, sgn = 1;
    		char c;
    		
    		while(! isdigit(c = getchar()))
    			if(c == '-')
    				sgn *= -1;
    		
    		while(isdigit(c))
    			a = a * 10 + c - '0', c = getchar();
    		
    		return a * sgn;
    	}
    }
    
    struct trieTree
    {
    	int pw[18], hd[N], tp, ltr[N], hsh[N][18];
    
    	inline void initialize()
    	{
    		memset(hd, -1, sizeof(hd));
    		tp = 0;
    		ltr[1] = 0;
    
    		for(int i = 0; i < 18; ++ i)
    			pw[i] = modPower(K, 1 << i);
    		
    		memset(hsh, 0, sizeof(hsh));
    	}
    
    	struct edge
    	{
    		int v, nxt;
    	}edg[N];
    
    	inline void addEdge(int u, int v, int c)
    	{
    		edg[tp].v = v, edg[tp].nxt = hd[u];
    		hd[u] = tp ++;
    		ltr[v] = c;
    	}
    
    	int dep[N], anc[N][18];
    
    	void DFS(int u, int pre)
    	{
    		anc[u][0] = pre, hsh[u][0] = ltr[u];
    
    		for(int i = 1; i < 18; ++ i)
    			anc[u][i] = anc[anc[u][i - 1]][i - 1], hsh[u][i] = (hsh[anc[u][i - 1]][i - 1] + (long long)hsh[u][i - 1] * pw[i - 1] % MOD) % MOD;
    
    		for(int i = hd[u]; ~ i; i = edg[i].nxt)
    			dep[edg[i].v] = dep[u] + 1, DFS(edg[i].v, u);
    	}
    
    	int sa[N], rk[N], ht[N];
    
    	inline int getLCP(int u, int v)
    	{
    		int res = 0;
    
    		for(int i = 18 - 1; ~ i; -- i)
    			if(hsh[u][i] == hsh[v][i])
    				u = anc[u][i], v = anc[v][i], res += 1 << i;
    		
    		return res;
    	}
    
    	inline void getSuffixArray()
    	{
    		dep[1] = 0;
    		DFS(1, 1);
    		static int sum[N];
    		memset(sum, 0, sizeof(sum));
    
    		for(int i = 1; i <= n; ++ i)
    			++ sum[ltr[i]];
    		
    		for(int i = 1; i < N; ++ i)
    			sum[i] += sum[i - 1];
    
    		for(int i = 1; i <= n; ++ i)
    			sa[-- sum[ltr[i]]] = i;
    
    		int p = 0;
    		rk[sa[0]] = p;
    
    		for(int i = 1; i < n; ++ i)
    			rk[sa[i]] = ltr[sa[i]] == ltr[sa[i - 1]] ? p : ++ p;
    
    		int lim = p + 1;
    
    		for(int len = 0; lim < n; ++ len)
    		{
    			static std::vector<int> suc[N];
    			
    			for(int i = 1; i <= n; ++ i)
    				suc[i].clear();
    			
    			for(int i = 0; i < n; ++ i)
    				if(dep[sa[i]] >= 1 << len)
    					suc[anc[sa[i]][len]].push_back(sa[i]);
    				
    			static int tmpSa[N];
    			int p = 0;
    
    			for(int i = 0; i < n; ++ i)
    				if(dep[sa[i]] < 1 << len)
    					tmpSa[p ++] = sa[i];
    
    			for(int i = 0; i < n; ++ i)
    				for(std::vector<int>::iterator itr = suc[sa[i]].begin(); itr != suc[sa[i]].end(); ++ itr)
    					tmpSa[p ++] = *itr;
    
    			memset(sum, 0, sizeof(sum));
    
    			for(int i = 1; i <= n; ++ i)
    				++ sum[rk[i]];
    			
    			for(int i = 1; i < N; ++ i)
    				sum[i] += sum[i - 1];
    
    			for(int i = n - 1; ~ i; -- i)
    				sa[-- sum[rk[tmpSa[i]]]] = tmpSa[i];
    
    			static int tmpRk[N];
    			memcpy(tmpRk, rk, sizeof(rk));
    			rk[sa[0]] = p = 0;
    
    			for(int i = 1; i < n; ++ i)
    			{
    				if(tmpRk[sa[i]] != tmpRk[sa[i - 1]] || tmpRk[anc[sa[i]][len]] != tmpRk[anc[sa[i - 1]][len]])
    					++ p;
    
    				rk[sa[i]] = p;
    			}
    
    			lim = p + 1;
    		}
    
    		ht[0] = 0;
    
    		for(int i = 1; i <= n; ++ i)
    			if(rk[i])
    				ht[rk[i]] = getLCP(i, sa[rk[i] - 1]);
    	}
    	
    	int ST[N << 1][18];
    	
    	inline void getSparseTable()
    	{
    		memset(ST, 127, sizeof(ST));
    		
    		for(int i = 0; i < n; ++ i)
    			ST[i][0] = ht[i];
    		
    		for(int i = 1; i < 18; ++ i)
    			for(int j = 0; j < n; ++ j)
    				ST[j][i] = std::min(ST[j][i - 1], ST[j + (1 << i - 1)][i - 1]);
    	}
    
    	inline int getMin(int L, int R)
    	{
    		int tmp = log2(R - L + 1);
    		return std::min(ST[L][tmp], ST[R - (1 << tmp) + 1][tmp]);
    	}
    	
    	std::set<int> st[N];
    	
    	inline std::set<int>::iterator getLast(std::set<int>::iterator p)
    	{
    		return -- p;
    	}
    	
    	inline std::set<int>::iterator getNext(std::set<int>::iterator p)
    	{
    		return ++ p;
    	}
    
    	int DFS1(int u)
    	{
    		st[u].insert(rk[u]);
    		int res = 0;
    
    		for(int i = hd[u]; ~ i; i = edg[i].nxt)
    		{
    			int v = edg[i].v;
    			res = std::max(res, DFS1(v));
    
    			if(st[u].size() < st[v].size())
    				std::swap(st[u], st[v]);
    
    			for(std::set<int>::iterator itr = st[v].begin(); itr != st[v].end(); ++ itr)
    			{
    				st[u].insert(*itr);
    				std::set<int>::iterator p = st[u].find(*itr);
    
    				if(p != st[u].begin())
    					res = std::max(res, getMin(*getLast(p) + 1, *p) + dep[u]);
    
    				if(getNext(p) != st[u].end())
    					res = std::max(res, getMin(*p + 1, *getNext(p)) + dep[u]);
    			}
    		}
    
    		return res;
    	}
    	
    	inline int getAns()
    	{
    		for(int i = 1; i <= n; ++ i)
    			st[i].clear();
    
    		return DFS1(1);
    	}
    }org;
    
    int main()
    {
    	#ifndef ONLINE_JUDGE
    	freopen("recollection.in", "r", stdin);
    	freopen("recollection.out", "w", stdout);
    	#endif
    	
    	using namespace Zeonfai;
    	
    	n = getInt();
    	org.initialize();
    
    	for(int i = 2; i <= n; ++ i)
    	{
    		int pre = getInt(), c = getInt();
    		org.addEdge(pre, i, c + 1);
    	}
    
    	org.getSuffixArray();
    	org.getSparseTable();
    	printf("%d", org.getAns());
    }
    

    2017.8.10 第二次写这一道题

    #include <cstdio>
    #include <cctype>
    #include <vector>
    #include <set>
    #include <algorithm>
    #include <cstring>
     
    namespace Zeonfai
    {
        inline int getInt()
        {
            int a = 0, sgn = 1;
            char c;
            while(! isdigit(c = getchar())) if (c == '-') sgn *= -1;
            while(isdigit(c)) a = a * 10 + c - '0', c = getchar();
            return a * sgn;
        }
    }
    const int N = (int)2e5, LOG = 18, K = 47, MOD = (int)1e9 + 7;
    int n, ans = 0;
    int pw[LOG];
    inline int power(int a, int x)
    {
        int res = 1;
        for(; x; a = (long long)a * a % MOD, x >>= 1) if(x & 1) res = (long long)res * a % MOD;
        return res;
    }
    inline std::set<int>::iterator getPrevious(std::set<int>::iterator p)
    {
        return -- p;
    }
    inline std::set<int>::iterator getNext(std::set<int>::iterator p)
    {
        return ++ p;
    }
    struct trieTree
    {
        struct node
        {
            std::vector<node*> suc, pst[LOG];
            node *anc[LOG];
            int c, dep, rk, _rk;
            int hsh[LOG];
            inline node()
            {
                suc.clear();
                for(int i = 0; i < LOG; ++ i) pst[i].clear();
            }
        }nd[N + 1];
        inline void addEdge(int u, int v, int c)
        {
            nd[v].c = c; nd[u].suc.push_back(nd + v);
        }
        void DFS(node *u, node *pre)
        {
            u->dep = pre == NULL ? 0 : pre->dep + 1;
            u->anc[0] = pre;
            if(u->anc[0] != NULL) u->anc[0]->pst[0].push_back(u);
            u->hsh[0] = u->c;
            for(int i = 1; i < LOG; ++ i) if(u->anc[i - 1] != NULL)
            {
                u->anc[i] = u->anc[i - 1]->anc[i - 1];
                if(u->anc[i] != NULL) u->anc[i]->pst[i].push_back(u), u->hsh[i] = (u->hsh[i - 1] + (long long)u->anc[i - 1]->hsh[i - 1] * pw[i - 1] % MOD) % MOD;
            }
            for(auto v : u->suc) DFS(v, u);
        }
        node *SA[N];
        inline void sort()
        {
            static int sum[N];
            memset(sum, 0, sizeof(sum));
            for(int i = 1; i <= n; ++ i) ++ sum[nd[i].c];
            for(int i = 1; i <= 301; ++ i) sum[i] += sum[i - 1];
            for(int i = 1; i <= n; ++ i)
                SA[-- sum[nd[i].c]] = nd + i;
            int p = 0;
            SA[0]->rk = p;
            for(int i = 1; i < n; ++ i) SA[i]->rk = SA[i]->c == SA[i - 1]->c ? p : ++ p;
            int cnt = p + 1;
            for(int i = 0; cnt < n; ++ i)
            {
                p = 0;
                static node *tmpSA[N];
                for(int j = 1; j <= n; ++ j) if(nd[j].dep < 1 << i) tmpSA[p ++] = nd + j;
                for(int j = 0; j < n; ++ j) for(auto u : SA[j]->pst[i]) tmpSA[p ++] = u;
                memset(sum, 0, sizeof(sum));
                for(int j = 1; j <= n; ++ j) ++ sum[nd[j].rk];
                for(int j = 1; j < cnt; ++ j) sum[j] += sum[j - 1];
                for(int j = n - 1; ~ j; -- j) SA[-- sum[tmpSA[j]->rk]] = tmpSA[j];
                for(int j = 1; j <= n; ++ j) nd[j]._rk = nd[j].rk;
                p = 0;
                SA[0]->rk = p;
                for(int j = 1; j < n; ++ j)
                {
                    if(SA[j]->_rk != SA[j - 1]->_rk || SA[j - 1]->dep < 1 << i || SA[j - 1]->anc[i]->_rk != SA[j]->anc[i]->_rk) ++ p;
                    SA[j]->rk = p;
                }
                cnt = p + 1;
            }
        }
        inline int getLCP(node *u, node *v)
        {
            int res = 0;
            for(int i = LOG - 1; ~ i; -- i) if(u->dep >= 1 << i && v->dep >= 1 << i && u->hsh[i] == v->hsh[i])
                res += 1 << i, u = u->anc[i], v =v->anc[i];
            return res;
        }
        inline void merge(int dep, std::set<int> &a, std::set<int> &b)
        {
            if(a.size() < b.size()) std::swap(a, b);
            for(std::set<int>::iterator p = b.begin(); p != b.end(); ++ p)
            {
                a.insert(*p);
                std::set<int>::iterator tmp = a.find(*p);
                if(tmp != a.begin()) ans = std::max(ans, dep + getLCP(SA[*getPrevious(tmp)], SA[*p]));
                if(getNext(tmp) != a.end()) ans = std::max(ans, dep + getLCP(SA[*getNext(tmp)], SA[*p]));
            }
            b.clear();
        }
        std::set<int> getAnswer(node *u)
        {
            std::set<int> st; st.clear(); st.insert(u->rk);
            for(auto v : u->suc)
            {
                std::set<int> tmp = getAnswer(v);
                merge(u->dep, tmp, st);
            }
            return st;
        }
    }T;
    int main()
    {
     
        #ifndef ONLINE_JUDGE
     
        freopen("recollection.in", "r", stdin);
        freopen("recollection.out", "w", stdout);
     
        #endif
     
        using namespace Zeonfai;
        for(int i = 0; i < LOG; ++ i) pw[i] = power(K, 1 << i);
        n = getInt();
        for(int i = 2; i <= n; ++ i)
        {
            int pre = getInt(), c = getInt() + 1;
            T.addEdge(pre, i, c);
        }
        T.DFS(T.nd + 1, NULL);
        T.sort();
        T.getAnswer(T.nd + 1);
        printf("%d
    ", ans);
    }
    
  • 相关阅读:
    PHP脚本如何正确启用sg11安全组件?
    android修改系统时系统黑屏时不进入休眠状态
    计算机自考视频汇总【福利资料】[转]
    解决MySql报错:1130
    “领导想提拔你,看的从不是努力
    interTbale ___AlterTable
    MySQL数据库管理系统概述
    《分布式任务调度平台XXL-JOB》
    mysql 在线文档
    Oracle19c 数据库在线文档
  • 原文地址:https://www.cnblogs.com/ZeonfaiHo/p/6704014.html
Copyright © 2011-2022 走看看