Wednesday, 27 April 2016

E. Beautiful Subarrays
time limit per test
3 seconds
memory limit per test
512 megabytes
input
standard input
output
standard output
One day, ZS the Coder wrote down an array of integers a with elements a1,  a2,  ...,  an.
A subarray of the array a is a sequence al,  al  +  1,  ...,  ar for some integers (l,  r) such that 1  ≤  l  ≤  r  ≤  n. ZS the Coder thinks that a subarray of a is beautiful if the bitwise xor of all the elements in the subarray is at least k.
Help ZS the Coder find the number of beautiful subarrays of a!
Input
The first line contains two integers n and k (1 ≤ n ≤ 106, 1 ≤ k ≤ 109) — the number of elements in the array a and the value of the parameter k.
The second line contains n integers ai (0 ≤ ai ≤ 109) — the elements of the array a.
Output
Print the only integer c — the number of beautiful subarrays of the array a.
Examples
input
3 1
1 2 3
output
5
input
3 2
1 2 3
output
3
input
3 3
1 2 3
output
2






Explanation
XOR on subarrays always hint us towards tries.
The problem was suggested by Zi Song Yeoh zscoder.
The sign  is used for the binary operation for bitwise exclusive or.
Let si be the xor of the first i elements on the prefix of a. Then the interval (i, j] is beautiful if . Let's iterate over j from 1 ton and consider the values sj as the binary strings. On each iteration we should increase the answer by the value zj — the number of numbers si (i < j) so . To do that we can use the trie data structure. Let's store in the trie all the values si for i < j. Besides the structure of the trie we should also store in each vertex the number of leaves in the subtree of that vertex (it can be easily done during adding of each binary string). To calculate the value zj let's go down by the trie from the root. Let's accumulate the value curequals to the xor of the prefix of the value sj with the already passed in the trie path. Let the current bit in sj be equal to b and i be the depth of the current vertex in the trie. If the number cur + 2i ≥ k then we can increase zj by the number of leaves in vertex , because all the leaves in the subtree of tha vertex correspond to the values si that for sure gives . After that we should go down in the subtree b. Otherwise if cur + 2i < k then we should simply go down to the subtree  and recalculate the valuecur = cur + 2i.
C++ solution
Comlpexity by the time and the memory: O(nlogX), where X is the maximal xor on the prefixes.
       ************************************HERE GOES MY CODE **********************************
#include<bits/stdc++.h>
using namespace std;
#define ll long long int
ll a[1000010]; 
class node
{
   public:
    node *lt,*rt;
    int sub;
    node()
    {
       lt=NULL;
       rt=NULL;
       sub=0;
}
};
void insert(node *root,ll val)
{
   for(int i=32;i>=0;i--)
   {
        if(val>>i&1)
        {
             if(root->rt==NULL)
             {
                   root->rt=new node();
 }
 root=root->rt;
 root->sub++;
}
else
            if(root->lt==NULL)
{
      root->lt=new node();
}
root=root->lt;
root->sub++;
}
}
}
ll query(node *root,ll val,ll K)
{
ll ret=0;
       for(int i=32;i>=0;i--)
       {
            int v=val>>i&1;
int k=K>>i&1;
node *temp;
if(v==1 && k==0)
{
        temp=root->lt;
if(temp!=NULL)
{
    ret+=temp->sub;
// cout<<"ad ledt subtree "<<endl;
}
if(root->rt!=NULL)
{
  root=root->rt;
 // cout<<"go to rt "<<endl;
}
else
{
//cout<<"direct ret "<<endl;
          return ret;
}    
}
else if(v==1 && k==1)
{
      if(root->lt!=NULL)
{
// cout<<"only option go to lt "<<endl;
  root=root->lt;
}
else 
//cout<<"return ret "<<endl;
return ret;  
   }
}
else if(v==0 && k==0)
{
      temp=root->rt;
      if(temp!=NULL)
      {
       //cout<<"add values on rt subtree "<<endl;
         ret+=temp->sub;
  }
  if(root->lt!=NULL)
  {
  //cout<<"go to lefct "<<endl;
       root=root->lt;
  }
  else
  { 
  //cout<<"else  return ret "<<endl;
 return ret;
   }
}
else
{
       if(root->rt!=NULL)
       {
       // cout<<"tru and go to rt "<<endl;
            root=root->rt;
}
else
{ //  cout<<"elset return ret "<<endl;
  return ret;
    }
if(i==0)
{
     ret+=root->sub;
 } 
}
return ret;
}
int main()
{
  int n;
  cin>>n;
  ll k;
  cin>>k;
  node *root=new node();
  for(int i=1;i<=n;i++)
  {
   scanf("%lld",&a[i]);
  }
  insert(root,0);
//  cout<<" inserted "<<endl;
  int pre=0;
  ll ans=0;
  for(int i=1;i<=n;i++)
  {
           pre=pre^a[i];
           ans+=query(root,pre,k);
insert(root,pre);  
  }
  cout<<ans<<endl;
}


Sunday, 24 April 2016

Path containing K Nodes 
Solved

Problem code: KNODES

All submissions for this problem are available.

Read problems statements in Mandarin Chinese and Russian as well.

You are given a tree.
You have to execute numerous queries on this tree. In a query, you will be given K nodes and you need to find if there is a path in the tree which contains all these K nodes.
If there is a path containing these K nodes, then output Yes. Otherwise, output No.

Input

First line contains T, number of test cases to follow.
First line of each test case contains an integer N which represents the number of nodes in the tree.
Next N-1 lines contain the description of the tree. Each line contains 2 space separated integers implying that there is an edge between these two nodes.
Next line contains Q, number of path queries to follow.
First line of each query contains an integer K.
Second line contains K space separated nodes.

Output

For each query, output Yes if there is a path containing the K query nodes. Otherwise, output No.

Constraints

  • 1 ≤ N ≤ 105
  • 1 ≤ Sum of N over all test cases ≤ 105
  • 1 ≤ T ≤ 500
  • 3 ≤ K ≤ N
  • 1 ≤ Sum of K over all test cases and queries ≤ 106
  • Nodes are numbered from 1

Example

Input:

1
10
3 1
5 7
4 6
10 4
8 9
2 1
3 4
8 5
5 3
4
3
8 10 3
4
8 7 9 6
3
2 1 6
3
6 2 5

Output:

Yes
No
Yes
No

Explanation:

Query 1: The path corresponding to it is 8->5->3->4->10.
Query 2: There does not exists any path joining all 4.

Quick Explanation:

We will try building a path to solve this problem. A path will have 2 end points and we will first try to find out these two end points (say D and RD) and then try to check if all the nodes lie either on the path from D to the root or from RD to root.
Now, if the above conditions are satisfied, we need to check whether they still form a pair or not. Solution contains a detailed explanation of the approach.

Solution:

Fix any node as root of the tree. Then do a depth-first traversal and store 3 things for each node:
  1. Depth of the node : It is the distance of the node from the root.
  2. Start time of the dfs : It is the time when the dfs started on the node.
  3. End time of the dfs : It is the time when the dfs ended on the node.
You can increase time by 1 when moving to an unvisited node.
Now for all the given K nodes, find the deepest node and the node closest to root.
Let the deepest node be D and let the node closest to root be S.
We will now partition the set of K nodes into two disjoint sets A and B.
Set A will contain nodes which are on the path from root to D. Set B will contain the remaining nodes.
How to make set A?
If the start time of node X is before the start time of node D and the end time of node X is after the end time of node D then node X belongs to set A. [Using properties of DFS]
If set B was a null set, then our answer is "Yes".
Find the deepest node in the set B, let us name it as RD. [Deepest node in the remaining nodes/set B]
Now again follow the same procedure to partition the set B into C and E where set C contains nodes from set Bwhich are on the path from RD to root of the tree.
If set E is not empty, then our answer is "No". ( Reasons ? : I hope the readers to use pen and paper to draw a diagram and understand how things are moving, from there it will be trivial to find the reason)
Now, Find the LCA of D and RD. Let us call this node as L.
L must lie between S (smallest depth node in K nodes) and root of the tree for a valid path to exists.
Reason:
If S lies in between root and L, then there does not exist any path.
L must be repeated twice in the journey from D to RD. Hence not a path.
Time complexity of this algorithm is O(N) (for dfs part per test case) + O(K+log(N)) (per query).


                 ******************  THE CODE GOES HERE **************************************************


#include<bits/stdc++.h>
using namespace std;
list<int> arr[100010];
#define mp make_pair
#define pb push_back
#define ff first
#define ss second
int tmi=0;
int level[100010];
int T[100010];
int dp[100010][25];
int n;
int sttime[100010];
int ettime[100010];
void pre()
{
   memset(dp,-1,sizeof(dp));
   //cout<<"here "<<endl;
   for(int i=1;i<=n;i++)
   {
     dp[i][0]=T[i];
 //    cout<<"set  oth ancestor of "<<i<<" as "<<T[i]<<endl;
}
for(int j=1;1<<j<=n;j++)
{
  for(int i=1;i<=n;i++)
  {
     if(dp[i][j-1]!=-1)
     {
           dp[i][j]=dp[dp[i][j-1]][j-1];  
}
  }
}
}
int flca(int p, int q)
{
//cout<<"levels "<<level[p]<<" "<<level[q]<<endl;
  if(level[p]<level[q])
  {
   swap(p,q);
  }
  int log;
  for(log=1;(1<<log)<=level[p];log++);
  log--;
  for (int i = log; i >= 0; i--)
          if (level[p] - (1 << i) >= level[q])
              p = dp[p][i];
   
      if (p == q)
          return p;
        //  cout<<"log  is "<<log<<endl;
           for (int i = log; i >= 0; i--)
           {
     // cout<<"to chek "<<i<<" th ancestor of "<<p<<" "<<q<<" they are "<<dp[p][i]<<" "<<dp[q][i]<<endl;
          if (dp[p][i] != -1 && dp[p][i] != dp[q][i])
          {
 
              p = dp[p][i], q = dp[q][i];
              //   cout<<"change p q to "<<p<<" "<<q<<endl;
}
             }
      return T[p];
}
void dfs(int root,int par,int lev)

{
 level[root]=lev;
 sttime[root]=tmi;
 T[root]=par;
 list<int> ::iterator it;
  for(it=arr[root].begin();it!=arr[root].end();it++)
     { 
         if(*it!=par)
 {
          tmi++;
  dfs(*it,root,lev+1);
 }  
 }
 ettime[root]=tmi;
}
bool ischild(int ch,int an)
{
      if(sttime[ch]>=sttime[an] && ettime[ch]<=ettime[an])
      return 1;
      return 0;
}
int main()
{
int t;
cin>>t;
while(t--)
{
     
 //int n;
 tmi=0;
 cin>>n;
 for(int i=1;i<=n;i++)
 arr[i].clear();
 for(int i=0;i<n-1;i++)
 {
   int aa,bb;
   scanf("%d %d",&aa,&bb);
   arr[aa].pb(bb);
   arr[bb].pb(aa);
 }
 dfs(1,0,0);
 pre();
 int q;
 cin>>q;
 while(q--)
 {
      int tt;
      scanf("%d",&tt);
      vector<int> v;
  for(int i=0;i<tt;i++)
      {
       int aa;
       scanf("%d",&aa);
       v.pb(aa);
      // mark[i]=0;
}
vector<int> a,b,c,d,e;
int lev=0;
int deep1=0;
int lvmi=1000000;
int sm=-1;
for(int i=0;i<tt;i++)
{
    if(level[v[i]]>lev)
    {
      deep1=v[i];
      lev=level[deep1];
}
if(level[v[i]]<lvmi)
{
 sm=v[i];
 lvmi=level[sm];
}
}
// cout<<"deep 1 "<<deep1<<endl;
for(int i=0;i<tt;i++)
{
 int nd=v[i];
if(sttime[nd]<=sttime[deep1] && ettime[nd]>=ettime[deep1])
{
     a.pb(nd);
//      cout<<"in a "<<nd<<endl;
 }
 else
 {
   b.pb(nd);
 }
}
if(b.size()==0)
{
 printf("Yes\n");
 continue;
}
int sz=b.size();
lev=0;
int deep2=-1;
for(int i=0;i<sz;i++)
{
     int nd=b[i];
 if(level[nd]>lev)
 {
   lev=level[nd];
      deep2=nd;  
 }
}
for(int i=0;i<sz;i++)
{
   int nd=b[i];
if(sttime[nd]<=sttime[deep2] && ettime[nd]>=ettime[deep2])
{
     c.pb(nd);
//      cout<<"in a "<<nd<<endl;
 }
 else
 {
   d.pb(nd);
 }
}
if(d.size()!=0)
{
 printf("No\n");
 continue;
}
    int res=c.size();
int lca=flca(deep2,deep1);
if(ischild(sm,lca))
{
 printf("Yes\n");
 
}
else printf("No\n");  
}
// cout<<"deep2 "<<deep2<<endl;
 
      }
      return 0;
      
}